Przeglądaj źródła

refactor(admin-ui): Move common list functionality to base class

Michael Bromley 2 lat temu
rodzic
commit
8d35175fb7
27 zmienionych plików z 232 dodań i 501 usunięć
  1. 5 86
      packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts
  2. 6 7
      packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts
  3. 28 2
      packages/admin-ui/src/lib/core/src/common/base-list.component.ts
  4. 23 1
      packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts
  5. 0 1
      packages/admin-ui/src/lib/core/src/providers/local-storage/local-storage.service.ts
  6. 9 1
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.html
  7. 9 34
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts
  8. 4 1
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.html
  9. 3 26
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts
  10. 7 7
      packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.html
  11. 6 37
      packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts
  12. 13 7
      packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.html
  13. 5 36
      packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts
  14. 16 10
      packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.html
  15. 4 31
      packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts
  16. 14 0
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.html
  17. 4 32
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts
  18. 29 22
      packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.html
  19. 4 35
      packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts
  20. 3 0
      packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.html
  21. 3 31
      packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts
  22. 12 3
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.html
  23. 4 26
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts
  24. 8 3
      packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.html
  25. 4 31
      packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts
  26. 5 0
      packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.html
  27. 4 31
      packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts

+ 5 - 86
packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts

@@ -1,27 +1,20 @@
 import { Component, OnInit } from '@angular/core';
-import { UntypedFormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
-    DeletionResult,
+    DataTableService,
     FacetFilterParameter,
     FacetSortParameter,
     GetFacetListQuery,
-    getOrderStateTranslationToken,
     ItemOf,
     LanguageCode,
     ModalService,
     NotificationService,
-    OrderFilterParameter,
-    SelectionManager,
     ServerConfigService,
 } from '@vendure/admin-ui/core';
-import { SortOrder } from '@vendure/common/lib/generated-types';
-import { EMPTY, merge, Observable } from 'rxjs';
-import { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
+import { Observable } from 'rxjs';
 
 @Component({
     selector: 'vdr-facet-list',
@@ -32,31 +25,14 @@ export class FacetListComponent
     extends BaseListComponent<GetFacetListQuery, ItemOf<GetFacetListQuery, 'facets'>>
     implements OnInit
 {
-    searchTermControl = new UntypedFormControl('');
     availableLanguages$: Observable<LanguageCode[]>;
     contentLanguage$: Observable<LanguageCode>;
     readonly initialLimit = 3;
     displayLimit: { [id: string]: number } = {};
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
 
     readonly filters = this.dataTableService
         .createFilterCollection<FacetFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'visibility',
             type: { kind: 'boolean' },
@@ -110,15 +86,8 @@ export class FacetListComponent
         this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();
         this.contentLanguage$ = this.dataService.client
             .uiState()
-            .mapStream(({ uiState }) => uiState.contentLanguage)
-            .pipe(tap(() => this.refresh()));
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => 2 <= value.length || value.length === 0),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+            .mapStream(({ uiState }) => uiState.contentLanguage);
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges, this.contentLanguage$);
     }
 
     toggleDisplayLimit(facet: ItemOf<GetFacetListQuery, 'facets'>) {
@@ -129,57 +98,7 @@ export class FacetListComponent
         }
     }
 
-    deleteFacet(facetValueId: string) {
-        this.showModalAndDelete(facetValueId)
-            .pipe(
-                switchMap(response => {
-                    if (response.result === DeletionResult.DELETED) {
-                        return [true];
-                    } else {
-                        return this.showModalAndDelete(facetValueId, response.message || '').pipe(
-                            map(r => r.result === DeletionResult.DELETED),
-                        );
-                    }
-                }),
-                // Refresh the cached facets to reflect the changes
-                switchMap(() => this.dataService.facet.getAllFacets().single$),
-            )
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'FacetValue',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'FacetValue',
-                    });
-                },
-            );
-    }
-
     setLanguage(code: LanguageCode) {
         this.dataService.client.setContentLanguage(code).subscribe();
     }
-
-    private showModalAndDelete(facetId: string, message?: string) {
-        return this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-facet'),
-                body: message,
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    {
-                        type: 'danger',
-                        label: message ? _('common.force-delete') : _('common.delete'),
-                        returnValue: true,
-                    },
-                ],
-            })
-            .pipe(
-                switchMap(res => (res ? this.dataService.facet.deleteFacet(facetId, !!message) : EMPTY)),
-                map(res => res.deleteFacet),
-            );
-    }
 }

+ 6 - 7
packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts

@@ -42,7 +42,12 @@ export class ProductListComponent
     availableLanguages$: Observable<LanguageCode[]>;
     contentLanguage$: Observable<LanguageCode>;
     pendingSearchIndexUpdates = 0;
-    selectionManager: SelectionManager<SearchItem>;
+    selectionManager = new SelectionManager<SearchItem>({
+        multiSelect: true,
+        itemsAreEqual: (a, b) =>
+            this.groupByProduct ? a.productId === b.productId : a.productVariantId === b.productVariantId,
+        additiveMode: true,
+    });
     readonly filters = this.dataTableFilterService
         .createFilterCollection<SearchInput>()
         .addFilter({
@@ -102,12 +107,6 @@ export class ProductListComponent
                 } as SearchInput,
             }),
         );
-        this.selectionManager = new SelectionManager({
-            multiSelect: true,
-            itemsAreEqual: (a, b) =>
-                this.groupByProduct ? a.productId === b.productId : a.productVariantId === b.productVariantId,
-            additiveMode: true,
-        });
     }
 
     ngOnInit() {

+ 28 - 2
packages/admin-ui/src/lib/core/src/common/base-list.component.ts

@@ -1,13 +1,17 @@
 import { Directive, OnDestroy, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
 import { ActivatedRoute, QueryParamsHandling, Router } from '@angular/router';
-import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';
-import { distinctUntilChanged, map, shareReplay, takeUntil } from 'rxjs/operators';
+import { BehaviorSubject, combineLatest, merge, Observable, Subject } from 'rxjs';
+import { debounceTime, distinctUntilChanged, filter, map, shareReplay, takeUntil } from 'rxjs/operators';
 
 import { QueryResult } from '../data/query-result';
+import { GetFacetListQuery } from './generated-types';
+import { SelectionManager } from './utilities/selection-manager';
 
 export type ListQueryFn<R> = (take: number, skip: number, ...args: any[]) => QueryResult<R, any>;
 export type MappingFn<T, R> = (result: R) => { items: T[]; totalItems: number };
 export type OnPageChangeFn<V> = (skip: number, take: number) => V;
+
 /**
  * Unwraps a query that returns a paginated list with an "items" property,
  * returning the type of one of the items in the array.
@@ -17,6 +21,7 @@ export type ItemOf<T, K extends keyof T> = T[K] extends { items: infer R }
         ? R[number]
         : R
     : never;
+
 /**
  * @description
  * This is a base class which implements the logic required to fetch and manipulate
@@ -88,6 +93,12 @@ export type ItemOf<T, K extends keyof T> = T[K] extends { items: infer R }
 export class BaseListComponent<ResultType, ItemType, VariableType extends Record<string, any> = any>
     implements OnInit, OnDestroy
 {
+    searchTermControl = new FormControl('');
+    selectionManager = new SelectionManager<any>({
+        multiSelect: true,
+        itemsAreEqual: (a, b) => a.id === b.id,
+        additiveMode: true,
+    });
     result$: Observable<ResultType>;
     items$: Observable<ItemType[]>;
     totalItems$: Observable<number>;
@@ -158,6 +169,21 @@ export class BaseListComponent<ResultType, ItemType, VariableType extends Record
             .subscribe(fetchPage);
     }
 
+    /**
+     * @description
+     * Accepts a list of Observables which will trigger a refresh of the list when any of them emit.
+     */
+    protected refreshListOnChanges(...streams: Array<Observable<any>>) {
+        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
+            filter(value => value !== null && (2 < value.length || value.length === 0)),
+            debounceTime(250),
+        );
+
+        merge(searchTerm$, ...streams)
+            .pipe(takeUntil(this.destroy$))
+            .subscribe(() => this.refresh$.next(undefined));
+    }
+
     /** @internal */
     ngOnDestroy() {
         this.destroy$.next();

+ 23 - 1
packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts

@@ -1,8 +1,9 @@
 import { ActivatedRoute, Router } from '@angular/router';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import { assertNever } from '@vendure/common/lib/shared-utils';
 import { Subject } from 'rxjs';
 import extend from 'just-extend';
-import { NumberOperators, StringOperators } from '../../common/generated-types';
+import { DateOperators, NumberOperators, StringOperators } from '../../common/generated-types';
 import {
     DataTableFilter,
     DataTableFilterBooleanType,
@@ -82,6 +83,27 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         return this;
     }
 
+    addDateFilters(): FilterInput extends {
+        createdAt?: DateOperators | null;
+        updatedAt?: DateOperators | null;
+    }
+        ? DataTableFilterCollection<FilterInput>
+        : never {
+        this.addFilter({
+            name: 'createdAt',
+            type: { kind: 'dateRange' },
+            label: _('common.created-at'),
+            filterField: 'createdAt',
+        });
+        this.addFilter({
+            name: 'updatedAt',
+            type: { kind: 'dateRange' },
+            label: _('common.updated-at'),
+            filterField: 'updatedAt',
+        });
+        return this as any;
+    }
+
     getFilter(name: string): DataTableFilter<FilterInput> | undefined {
         return this.#filters.find(f => f.name === name);
     }

+ 0 - 1
packages/admin-ui/src/lib/core/src/providers/local-storage/local-storage.service.ts

@@ -17,7 +17,6 @@ export type LocalStorageTypeMap = {
     uiLanguageCode: LanguageCode;
     uiLocale: string | undefined;
     contentLanguageCode: LanguageCode;
-    orderListLastCustomFilters: any;
     dashboardWidgetLayout: WidgetLayoutDefinition;
     activeTheme: string;
     livePreviewCollectionContents: boolean;

+ 9 - 1
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.html

@@ -26,9 +26,17 @@
             [selectionManager]="selectionManager"
         ></vdr-bulk-action-menu>
         <vdr-dt2-search
-            [searchTermControl]="searchTerm"
+            [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'customer.search-customers-by-email-last-name-postal-code' | translate"
         ></vdr-dt2-search>
+        <vdr-dt2-column
+            [heading]="'common.id' | translate"
+            [hiddenByDefault]="true"
+        >
+            <ng-template let-customer="item">
+                {{ customer.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 9 - 34
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts

@@ -1,5 +1,4 @@
 import { Component, OnInit } from '@angular/core';
-import { UntypedFormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -7,16 +6,15 @@ import {
     CustomerFilterParameter,
     CustomerSortParameter,
     DataService,
+    DataTableService,
     GetCustomerListQuery,
     ItemOf,
     LogicalOperator,
     ModalService,
     NotificationService,
-    SelectionManager,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, switchMap, takeUntil } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
+import { EMPTY } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-customer-list',
@@ -27,26 +25,9 @@ export class CustomerListComponent
     extends BaseListComponent<GetCustomerListQuery, ItemOf<GetCustomerListQuery, 'customers'>>
     implements OnInit
 {
-    searchTerm = new UntypedFormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetCustomerListQuery, 'customers'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
     readonly filters = this.dataTableService
         .createFilterCollection<CustomerFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'firstName',
             type: { kind: 'text' },
@@ -94,17 +75,17 @@ export class CustomerListComponent
                     take,
                     filter: {
                         emailAddress: {
-                            contains: this.searchTerm.value,
+                            contains: this.searchTermControl.value,
                         },
                         lastName: {
-                            contains: this.searchTerm.value,
+                            contains: this.searchTermControl.value,
                         },
                         postalCode: {
-                            contains: this.searchTerm.value,
+                            contains: this.searchTermControl.value,
                         },
                         ...this.filters.createFilterInput(),
                     },
-                    filterOperator: this.searchTerm.value ? LogicalOperator.OR : LogicalOperator.AND,
+                    filterOperator: this.searchTermControl.value ? LogicalOperator.OR : LogicalOperator.AND,
                     sort: this.sorts.createSortInput(),
                 },
             }),
@@ -113,13 +94,7 @@ export class CustomerListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTerm.valueChanges.pipe(
-            filter(value => 2 < value.length || value.length === 0),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteCustomer(customer: ItemOf<GetCustomerListQuery, 'customers'>) {

+ 4 - 1
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.html

@@ -26,9 +26,12 @@
             [selectionManager]="selectionManager"
         />
         <vdr-dt2-search
-            [searchTermControl]="searchTerm"
+            [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'marketing.search-by-name-or-coupon-code' | translate"
         />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-promotion="item">{{ promotion.id }}</ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 3 - 26
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts

@@ -34,27 +34,9 @@ export class PromotionListComponent
     extends BaseListComponent<GetPromotionListQuery, ItemOf<GetPromotionListQuery, 'promotions'>>
     implements OnInit
 {
-    searchTerm = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetPromotionListQuery, 'promotions'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<PromotionFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'startsAt',
             type: { kind: 'dateRange' },
@@ -123,18 +105,13 @@ export class PromotionListComponent
         super.setQueryFn(
             (...args: any[]) => this.dataService.promotion.getPromotions(...args).refetchOnChannelChange(),
             data => data.promotions,
-            (skip, take) => this.createQueryOptions(skip, take, this.searchTerm.value),
+            (skip, take) => this.createQueryOptions(skip, take, this.searchTermControl.value),
         );
     }
 
     ngOnInit(): void {
         super.ngOnInit();
-        const searchTerm$ = this.searchTerm.valueChanges.pipe(debounceTime(250));
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(val => {
-                this.refresh();
-            });
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deletePromotion(promotionId: string) {

+ 7 - 7
packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.html

@@ -30,9 +30,14 @@
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
         <vdr-dt2-search
-            [searchTermControl]="searchControl"
+            [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'order.search-by-order-filters' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.created-at' | translate" [hiddenByDefault]="true">
+            <ng-template let-order="item">
+                {{ order.createdAt | localeDate : 'short' }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column [heading]="'common.code' | translate" [optional]="false">
             <ng-template let-order="item">
                 <a class="button-ghost" [routerLink]="['./', order.id]"
@@ -64,11 +69,6 @@
                 {{ order.totalWithTax | localeCurrency : order.currencyCode }}
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column [heading]="'common.created-at' | translate" [hiddenByDefault]="true">
-            <ng-template let-order="item">
-                {{ order.createdAt | localeDate : 'short' }}
-            </ng-template>
-        </vdr-dt2-column>
         <vdr-dt2-column [heading]="'common.updated-at' | translate">
             <ng-template let-order="item">
                 {{ order.updatedAt | timeAgo }}

+ 6 - 37
packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts

@@ -1,28 +1,23 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { UntypedFormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     ChannelService,
     DataService,
-    FacetSortParameter,
+    DataTableService,
     GetOrderListQuery,
     getOrderStateTranslationToken,
     ItemOf,
     LocalStorageService,
-    LogicalOperator,
     OrderFilterParameter,
     OrderListOptions,
     OrderSortParameter,
     OrderType,
     ServerConfigService,
-    SortOrder,
 } from '@vendure/admin-ui/core';
 import { Order } from '@vendure/common/lib/generated-types';
-import { merge } from 'rxjs';
-import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
+import { tap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-order-list',
@@ -34,23 +29,11 @@ export class OrderListComponent
     extends BaseListComponent<GetOrderListQuery, ItemOf<GetOrderListQuery, 'orders'>>
     implements OnInit
 {
-    searchControl = new UntypedFormControl('');
     orderStates = this.serverConfigService.getOrderProcessStates().map(item => item.name);
 
     readonly filters = this.dataTableService
         .createFilterCollection<OrderFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'active',
             type: { kind: 'boolean' },
@@ -121,7 +104,7 @@ export class OrderListComponent
             (take, skip) => this.dataService.order.getOrders({ take, skip }).refetchOnChannelChange(),
             data => data.orders,
             // eslint-disable-next-line @typescript-eslint/no-shadow
-            (skip, take) => this.createQueryOptions(skip, take, this.searchControl.value),
+            (skip, take) => this.createQueryOptions(skip, take, this.searchTermControl.value),
         );
         this.canCreateDraftOrder = !!this.serverConfigService
             .getOrderProcessStates()
@@ -131,31 +114,17 @@ export class OrderListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const lastFilters = this.localStorageService.get('orderListLastCustomFilters');
-        if (lastFilters) {
-            this.setQueryParam(lastFilters, { replaceUrl: true });
-        }
-        const searchTerms$ = merge(this.searchControl.valueChanges).pipe(
-            filter(value => 2 < value.length || value.length === 0),
-            debounceTime(250),
-        );
         const isDefaultChannel$ = this.channelService.defaultChannelIsActive$.pipe(
             tap(isDefault => (this.activeChannelIsDefaultChannel = isDefault)),
         );
-        merge(searchTerms$, isDefaultChannel$, this.route.queryParamMap, this.filters.valueChanges)
-            .pipe(debounceTime(50), takeUntil(this.destroy$))
-            .subscribe(val => {
-                this.refresh();
-            });
-
-        const queryParamMap = this.route.snapshot.queryParamMap;
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges, isDefaultChannel$);
     }
 
     private createQueryOptions(
         // eslint-disable-next-line @typescript-eslint/no-shadow
         skip: number,
         take: number,
-        searchTerm: string,
+        searchTerm: string | null,
     ): { options: OrderListOptions } {
         let filterInput = this.filters.createFilterInput();
         if (this.activeChannelIsDefaultChannel) {

+ 13 - 7
packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.html

@@ -23,11 +23,16 @@
             locationId="administrator-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
-        ></vdr-bulk-action-menu>
+        />
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-administrator="item">
+                {{ administrator.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"
@@ -46,7 +51,11 @@
                 {{ administrator.updatedAt | localeDate : 'short' }}
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column [heading]="'common.name' | translate" [optional]="false" [sort]="sorts.get('lastName')">
+        <vdr-dt2-column
+            [heading]="'common.name' | translate"
+            [optional]="false"
+            [sort]="sorts.get('lastName')"
+        >
             <ng-template let-administrator="item">
                 <a class="button-ghost" [routerLink]="['./', administrator.id]"
                     ><span>{{ administrator.firstName }} {{ administrator.lastName }}</span>
@@ -54,10 +63,7 @@
                 </a>
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column
-            [heading]="'settings.emailAddress' | translate"
-            [sort]="sorts.get('emailAddress')"
-        >
+        <vdr-dt2-column [heading]="'settings.emailAddress' | translate" [sort]="sorts.get('emailAddress')">
             <ng-template let-administrator="item">
                 {{ administrator.emailAddress }}
             </ng-template>

+ 5 - 36
packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts

@@ -1,5 +1,4 @@
 import { Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -7,20 +6,15 @@ import {
     AdministratorSortParameter,
     BaseListComponent,
     DataService,
+    DataTableService,
     GetAdministratorsQuery,
-    GetFacetListQuery,
     ItemOf,
     LogicalOperator,
     ModalService,
     NotificationService,
-    SelectionManager,
-    SellerFilterParameter,
-    SellerSortParameter,
-    SortOrder,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, switchMap, takeUntil } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
+import { EMPTY } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-administrator-list',
@@ -31,26 +25,9 @@ export class AdministratorListComponent
     extends BaseListComponent<GetAdministratorsQuery, ItemOf<GetAdministratorsQuery, 'administrators'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
     readonly filters = this.dataTableService
         .createFilterCollection<AdministratorFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'firstName',
             type: { kind: 'text' },
@@ -98,15 +75,7 @@ export class AdministratorListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerms$ = merge(this.searchTermControl.valueChanges).pipe(
-            filter(value => (value && 2 < value.length) || value?.length === 0),
-            debounceTime(250),
-        );
-        merge(searchTerms$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(val => {
-                this.refresh();
-            });
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteAdministrator(administrator: ItemOf<GetAdministratorsQuery, 'administrators'>) {

+ 16 - 10
packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.html

@@ -1,10 +1,14 @@
 <vdr-page-header>
     <vdr-page-title>
         <vdr-action-bar-items locationId="channel-list"></vdr-action-bar-items>
-        <a class="btn btn-primary" [routerLink]="['./create']" *vdrIfPermissions="['SuperAdmin', 'CreateChannel']">
-                  <clr-icon shape="plus"></clr-icon>
-                  {{ 'settings.create-new-channel' | translate }}
-              </a>
+        <a
+            class="btn btn-primary"
+            [routerLink]="['./create']"
+            *vdrIfPermissions="['SuperAdmin', 'CreateChannel']"
+        >
+            <clr-icon shape="plus"></clr-icon>
+            {{ 'settings.create-new-channel' | translate }}
+        </a>
     </vdr-page-title>
 </vdr-page-header>
 <vdr-page-body>
@@ -23,11 +27,16 @@
             locationId="channel-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
-        ></vdr-bulk-action-menu>
+        />
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-channel="item">
+                {{ channel.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"
@@ -54,10 +63,7 @@
                 </a>
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column
-            [heading]="'settings.channel-token' | translate"
-            [sort]="sorts.get('token')"
-        >
+        <vdr-dt2-column [heading]="'settings.channel-token' | translate" [sort]="sorts.get('token')">
             <ng-template let-channel="item">
                 {{ channel.token }}
             </ng-template>

+ 4 - 31
packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts

@@ -1,5 +1,4 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -8,15 +7,13 @@ import {
     ChannelSortParameter,
     DataService,
     GetChannelsQuery,
-    GetFacetListQuery,
     ItemOf,
     ModalService,
     NotificationService,
-    SelectionManager,
 } from '@vendure/admin-ui/core';
 import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, mergeMap, switchMap, takeUntil } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+import { mergeMap, switchMap } from 'rxjs/operators';
 import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
 
 @Component({
@@ -29,27 +26,9 @@ export class ChannelListComponent
     extends BaseListComponent<GetChannelsQuery, ItemOf<GetChannelsQuery, 'channels'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<ChannelFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'code',
             type: { kind: 'text' },
@@ -103,13 +82,7 @@ export class ChannelListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     isDefaultChannel(channelCode: string): boolean {

+ 14 - 0
packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.html

@@ -37,6 +37,20 @@
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
         />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-country="item">
+                {{ country.id }}
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column
+            [heading]="'common.created-at' | translate"
+            [hiddenByDefault]="true"
+            [sort]="sorts.get('createdAt')"
+        >
+            <ng-template let-country="item">
+                {{ country.createdAt | localeDate : 'short' }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 4 - 32
packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts

@@ -1,5 +1,4 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -10,18 +9,14 @@ import {
     DataTableService,
     DeletionResult,
     GetCountryListQuery,
-    GetFacetListQuery,
     ItemOf,
     LanguageCode,
     ModalService,
     NotificationService,
-    SelectionManager,
-    SellerFilterParameter,
-    SellerSortParameter,
     ServerConfigService,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge, Observable } from 'rxjs';
-import { debounceTime, filter, switchMap, takeUntil } from 'rxjs/operators';
+import { EMPTY, Observable } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-country-list',
@@ -33,29 +28,12 @@ export class CountryListComponent
     extends BaseListComponent<GetCountryListQuery, ItemOf<GetCountryListQuery, 'countries'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
     availableLanguages$: Observable<LanguageCode[]>;
     contentLanguage$: Observable<LanguageCode>;
 
     readonly filters = this.dataTableService
         .createFilterCollection<CountryFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },
@@ -114,13 +92,7 @@ export class CountryListComponent
             .mapStream(({ uiState }) => uiState.contentLanguage);
         this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();
 
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges, this.contentLanguage$);
     }
 
     setLanguage(code: LanguageCode) {

+ 29 - 22
packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.html

@@ -23,11 +23,16 @@
             locationId="role-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
-        ></vdr-bulk-action-menu>
+        />
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-role="item">
+                {{ role.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"
@@ -82,27 +87,29 @@
         <vdr-dt2-column [heading]="'settings.permissions' | translate">
             <ng-template let-role="item">
                 <ng-container *ngIf="!isDefaultRole(role); else defaultRole">
-              <div class="permissions-list">
-                    <vdr-chip
-                        *ngFor="let permission of role.permissions | slice : 0 : displayLimit[role.id] || 3"
-                        >{{ permission }}</vdr-chip
-                    >
-                    <button
-                        class="button-ghost"
-                        *ngIf="role.permissions.length > initialLimit"
-                        (click)="toggleDisplayLimit(role)"
-                    >
-                        <ng-container
-                            *ngIf="(displayLimit[role.id] || 0) < role.permissions.length; else collapse"
+                    <div class="permissions-list">
+                        <vdr-chip
+                            *ngFor="
+                                let permission of role.permissions | slice : 0 : displayLimit[role.id] || 3
+                            "
+                            >{{ permission }}</vdr-chip
+                        >
+                        <button
+                            class="button-ghost"
+                            *ngIf="role.permissions.length > initialLimit"
+                            (click)="toggleDisplayLimit(role)"
                         >
-                            <clr-icon shape="plus"></clr-icon>
-                            {{ role.permissions.length - initialLimit }}
-                        </ng-container>
-                        <ng-template #collapse>
-                            <clr-icon shape="minus"></clr-icon>
-                        </ng-template>
-                    </button>
-              </div>
+                            <ng-container
+                                *ngIf="(displayLimit[role.id] || 0) < role.permissions.length; else collapse"
+                            >
+                                <clr-icon shape="plus"></clr-icon>
+                                {{ role.permissions.length - initialLimit }}
+                            </ng-container>
+                            <ng-template #collapse>
+                                <clr-icon shape="minus"></clr-icon>
+                            </ng-template>
+                        </button>
+                    </div>
                 </ng-container>
                 <ng-template #defaultRole>
                     <span class="default-role-label">{{ 'settings.default-role-label' | translate }}</span>

+ 4 - 35
packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts

@@ -1,12 +1,10 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
     DataTableService,
-    GetFacetListQuery,
     GetRolesQuery,
     ItemOf,
     ModalService,
@@ -14,11 +12,10 @@ import {
     Role,
     RoleFilterParameter,
     RoleSortParameter,
-    SelectionManager,
 } from '@vendure/admin-ui/core';
 import { CUSTOMER_ROLE_CODE, SUPER_ADMIN_ROLE_CODE } from '@vendure/common/lib/shared-constants';
-import { EMPTY, merge, Observable } from 'rxjs';
-import { debounceTime, filter, map, switchMap, takeUntil } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-role-list',
@@ -32,28 +29,9 @@ export class RoleListComponent
 {
     readonly initialLimit = 3;
     displayLimit: { [id: string]: number } = {};
-    visibleRoles$: Observable<Array<ItemOf<GetRolesQuery, 'roles'>>>;
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<RoleFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'code',
             type: { kind: 'text' },
@@ -101,16 +79,7 @@ export class RoleListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        this.visibleRoles$ = this.items$.pipe(
-            map(roles => roles.filter(role => role.code !== CUSTOMER_ROLE_CODE)),
-        );
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     toggleDisplayLimit(role: ItemOf<GetRolesQuery, 'roles'>) {

+ 3 - 0
packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.html

@@ -32,6 +32,9 @@
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
         />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-seller="item">{{ seller.id }}</ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 3 - 31
packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts

@@ -1,22 +1,18 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
     DataTableService,
-    GetFacetListQuery,
     GetSellersQuery,
     ItemOf,
     ModalService,
     NotificationService,
-    SelectionManager,
     SellerFilterParameter,
     SellerSortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge, switchMap } from 'rxjs';
-import { debounceTime, filter, takeUntil } from 'rxjs/operators';
+import { EMPTY, switchMap } from 'rxjs';
 
 @Component({
     selector: 'vdr-seller-list',
@@ -28,27 +24,9 @@ export class SellerListComponent
     extends BaseListComponent<GetSellersQuery, ItemOf<GetSellersQuery, 'sellers'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<SellerFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .connectToRoute(this.route);
 
     readonly sorts = this.dataTableService
@@ -89,13 +67,7 @@ export class SellerListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteSeller(id: string) {

+ 12 - 3
packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.html

@@ -32,11 +32,16 @@
             locationId="shippingMethod-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
-        ></vdr-bulk-action-menu>
+        />
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-shippingMethod="item">
+                {{ shippingMethod.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"
@@ -68,7 +73,11 @@
                 {{ shippingMethod.code }}
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column [heading]="'common.description' | translate" [sort]="sorts.get('description')" [hiddenByDefault]="true">
+        <vdr-dt2-column
+            [heading]="'common.description' | translate"
+            [sort]="sorts.get('description')"
+            [hiddenByDefault]="true"
+        >
             <ng-template let-shippingMethod="item">
                 {{ shippingMethod.description }}
             </ng-template>

+ 4 - 26
packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts

@@ -47,26 +47,10 @@ export class ShippingMethodListComponent
     availableLanguages$: Observable<LanguageCode[]>;
     contentLanguage$: Observable<LanguageCode>;
     private fetchTestResult$ = new Subject<[TestAddress, TestOrderLine[]]>();
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
+
     readonly filters = this.dataTableService
         .createFilterCollection<ShippingMethodFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },
@@ -144,17 +128,11 @@ export class ShippingMethodListComponent
             .getActiveChannel()
             .mapStream(data => data.activeChannel);
         this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();
-
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
         this.contentLanguage$ = this.dataService.client
             .uiState()
             .mapStream(({ uiState }) => uiState.contentLanguage);
-        merge(searchTerm$, this.contentLanguage$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+
+        super.refreshListOnChanges(this.contentLanguage$, this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteShippingMethod(id: string) {

+ 8 - 3
packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.html

@@ -14,7 +14,7 @@
 <vdr-page-body>
     <vdr-data-table-2
         class="mt-2"
-        id="taxCategory-list"
+        id="tax-category-list"
         [items]="items$ | async"
         [itemsPerPage]="itemsPerPage$ | async"
         [totalItems]="totalItems$ | async"
@@ -27,11 +27,16 @@
             locationId="tax-category-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
-        ></vdr-bulk-action-menu>
+        />
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
-        ></vdr-dt2-search>
+        />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-taxCategory="item">
+                {{ taxCategory.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 4 - 31
packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts

@@ -1,5 +1,4 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -7,18 +6,16 @@ import {
     DataService,
     DataTableService,
     DeletionResult,
-    GetFacetListQuery,
     GetTaxCategoriesQuery,
     ItemOf,
     ModalService,
     NotificationService,
-    SelectionManager,
     TaxCategoryFilterParameter,
     TaxCategoryFragment,
     TaxCategorySortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, map, switchMap, takeUntil } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+import { map, switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-tax-list',
@@ -30,27 +27,9 @@ export class TaxCategoryListComponent
     extends BaseListComponent<GetTaxCategoriesQuery, ItemOf<GetTaxCategoriesQuery, 'taxCategories'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<TaxCategoryFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },
@@ -97,13 +76,7 @@ export class TaxCategoryListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteTaxCategory(taxCategory: TaxCategoryFragment) {

+ 5 - 0
packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.html

@@ -32,6 +32,11 @@
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
         />
+        <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+            <ng-template let-taxRate="item">
+                {{ taxRate.id }}
+            </ng-template>
+        </vdr-dt2-column>
         <vdr-dt2-column
             [heading]="'common.created-at' | translate"
             [hiddenByDefault]="true"

+ 4 - 31
packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts

@@ -1,5 +1,4 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -7,17 +6,15 @@ import {
     DataService,
     DataTableService,
     DeletionResult,
-    GetFacetListQuery,
     GetTaxRateListQuery,
     ItemOf,
     ModalService,
     NotificationService,
-    SelectionManager,
     TaxRateFilterParameter,
     TaxRateSortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, map, switchMap, takeUntil } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+import { map, switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-tax-rate-list',
@@ -29,27 +26,9 @@ export class TaxRateListComponent
     extends BaseListComponent<GetTaxRateListQuery, ItemOf<GetTaxRateListQuery, 'taxRates'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
     readonly filters = this.dataTableService
         .createFilterCollection<TaxRateFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },
@@ -109,13 +88,7 @@ export class TaxRateListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
+        super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
     deleteTaxRate(taxRate: ItemOf<GetTaxRateListQuery, 'taxRates'>) {