Przeglądaj źródła

feat(admin-ui): Implement pagination & filtering for customer groups

Closes #1360
Michael Bromley 3 lat temu
rodzic
commit
972123fcf2

+ 28 - 28
packages/admin-ui/i18n-coverage.json

@@ -1,70 +1,70 @@
 {
-  "generatedOn": "2022-07-22T11:18:02.830Z",
-  "lastCommit": "25b0af7028d086c8b6fc67c974865f5b01657358",
+  "generatedOn": "2022-07-22T14:11:18.272Z",
+  "lastCommit": "e663547f04d00cd601b028013bb23b80c4226ee1",
   "translationStatus": {
     "cs": {
-      "tokenCount": 652,
-      "translatedCount": 591,
+      "tokenCount": 653,
+      "translatedCount": 592,
       "percentage": 91
     },
     "de": {
-      "tokenCount": 652,
-      "translatedCount": 570,
+      "tokenCount": 653,
+      "translatedCount": 571,
       "percentage": 87
     },
     "en": {
-      "tokenCount": 652,
-      "translatedCount": 651,
+      "tokenCount": 653,
+      "translatedCount": 652,
       "percentage": 100
     },
     "es": {
-      "tokenCount": 652,
-      "translatedCount": 622,
+      "tokenCount": 653,
+      "translatedCount": 623,
       "percentage": 95
     },
     "fr": {
-      "tokenCount": 652,
-      "translatedCount": 612,
+      "tokenCount": 653,
+      "translatedCount": 613,
       "percentage": 94
     },
     "it": {
-      "tokenCount": 652,
-      "translatedCount": 620,
+      "tokenCount": 653,
+      "translatedCount": 621,
       "percentage": 95
     },
     "pl": {
-      "tokenCount": 652,
-      "translatedCount": 405,
+      "tokenCount": 653,
+      "translatedCount": 406,
       "percentage": 62
     },
     "pt_BR": {
-      "tokenCount": 652,
-      "translatedCount": 589,
+      "tokenCount": 653,
+      "translatedCount": 590,
       "percentage": 90
     },
     "pt_PT": {
-      "tokenCount": 652,
-      "translatedCount": 633,
+      "tokenCount": 653,
+      "translatedCount": 634,
       "percentage": 97
     },
     "ru": {
-      "tokenCount": 652,
-      "translatedCount": 619,
+      "tokenCount": 653,
+      "translatedCount": 620,
       "percentage": 95
     },
     "uk": {
-      "tokenCount": 652,
-      "translatedCount": 619,
+      "tokenCount": 653,
+      "translatedCount": 620,
       "percentage": 95
     },
     "zh_Hans": {
-      "tokenCount": 652,
-      "translatedCount": 557,
+      "tokenCount": 653,
+      "translatedCount": 558,
       "percentage": 85
     },
     "zh_Hant": {
-      "tokenCount": 652,
-      "translatedCount": 385,
+      "tokenCount": 653,
+      "translatedCount": 386,
       "percentage": 59
     }
   }

+ 1 - 1
packages/admin-ui/src/lib/core/src/shared/components/data-table/data-table.component.html

@@ -49,7 +49,7 @@
             [itemsPerPage]="itemsPerPage"
             (itemsPerPageChange)="itemsPerPageChange.emit($event)"
         ></vdr-items-per-page-controls>
-        <div>
+        <div *ngIf="totalItems" class="p5">
             {{ 'common.total-items' | translate: { currentStart, currentEnd, totalItems } }}
         </div>
 

+ 64 - 46
packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.html

@@ -1,5 +1,13 @@
 <vdr-action-bar>
-    <vdr-ab-left> </vdr-ab-left>
+    <vdr-ab-left>
+        <input
+            type="text"
+            name="emailSearchTerm"
+            [formControl]="searchTerm"
+            [placeholder]="'customer.search-by-group-name' | translate"
+            class="search-input ml3"
+        />
+    </vdr-ab-left>
     <vdr-ab-right>
         <vdr-action-bar-items locationId="customer-group-list"></vdr-action-bar-items>
         <button class="btn btn-primary" *vdrIfPermissions="'CreateCustomerGroup'" (click)="create()">
@@ -10,56 +18,66 @@
 </vdr-action-bar>
 <div class="group-wrapper">
     <div class="group-list">
-        <table
-            class="table mt0"
+        <vdr-data-table
             [class.expanded]="activeGroup$ | async"
-            *ngIf="!(listIsEmpty$ | async); else emptyPlaceholder"
+            [items]="items$ | async"
+            [itemsPerPage]="itemsPerPage$ | async"
+            [totalItems]="totalItems$ | async"
+            [currentPage]="currentPage$ | async"
+            (pageChange)="setPageNumber($event)"
+            (itemsPerPageChange)="setItemsPerPage($event)"
         >
+            <ng-template let-group="item">
+                <td class="left align-middle" [class.active]="group.id === activeGroupId">
+                    <vdr-entity-info [entity]="group"></vdr-entity-info>
+                </td>
+                <td class="left align-middle" [class.active]="group.id === activeGroupId">
+                    <vdr-chip [colorFrom]="group.id">{{ group.name }}</vdr-chip>
+                </td>
+                <td class="left align-middle" [class.active]="group.id === activeGroupId">
+                    <a
+                        class="btn btn-link btn-sm"
+                        [routerLink]="['./', { contents: group.id }]"
+                        queryParamsHandling="preserve"
+                    >
+                        <clr-icon shape="view-list"></clr-icon>
+                        {{ 'customer.view-group-members' | translate }}
+                    </a>
+                </td>
+                <td class="right align-middle" [class.active]="group.id === activeGroupId">
+                    <button class="btn btn-link btn-sm" (click)="update(group)">
+                        <clr-icon shape="edit"></clr-icon>
+                        {{ 'common.edit' | translate }}
+                    </button>
+                </td>
+                <td [class.active]="group.id === activeGroupId">
+                    <vdr-dropdown>
+                        <button type="button" class="btn btn-link btn-sm" vdrDropdownTrigger>
+                            {{ 'common.actions' | translate }}
+                            <clr-icon shape="caret down"></clr-icon>
+                        </button>
+                        <vdr-dropdown-menu vdrPosition="bottom-right">
+                            <button
+                                class="button"
+                                vdrDropdownItem
+                                (click)="delete(group.id)"
+                                [disabled]="!('DeleteCustomerGroup' | hasPermission)"
+                            >
+                                <clr-icon shape="trash" class="is-danger"></clr-icon>
+                                {{ 'common.delete' | translate }}
+                            </button>
+                        </vdr-dropdown-menu>
+                    </vdr-dropdown>
+                </td>
+            </ng-template>
+        </vdr-data-table>
+
+        <table class="table mt0" *ngIf="!(listIsEmpty$ | async); else emptyPlaceholder">
             <tbody>
                 <tr
-                    *ngFor="let group of groups$ | async"
+                    *ngFor="let group of items$ | async"
                     [class.active]="group.id === (activeGroup$ | async)?.id"
-                >
-                    <td class="left align-middle"><vdr-entity-info [entity]="group"></vdr-entity-info></td>
-                    <td class="left align-middle">
-                        <vdr-chip [colorFrom]="group.id">{{ group.name }}</vdr-chip>
-                    </td>
-                    <td class="text-right align-middle">
-                        <a
-                            class="btn btn-link btn-sm"
-                            [routerLink]="['./', { contents: group.id }]"
-                            queryParamsHandling="preserve"
-                        >
-                            <clr-icon shape="view-list"></clr-icon>
-                            {{ 'customer.view-group-members' | translate }}
-                        </a>
-                    </td>
-                    <td class="align-middle">
-                        <button class="btn btn-link btn-sm" (click)="update(group)">
-                            <clr-icon shape="edit"></clr-icon>
-                            {{ 'common.edit' | translate }}
-                        </button>
-                    </td>
-                    <td class="align-middle">
-                        <vdr-dropdown>
-                            <button type="button" class="btn btn-link btn-sm" vdrDropdownTrigger>
-                                {{ 'common.actions' | translate }}
-                                <clr-icon shape="caret down"></clr-icon>
-                            </button>
-                            <vdr-dropdown-menu vdrPosition="bottom-right">
-                                <button
-                                    class="button"
-                                    vdrDropdownItem
-                                    (click)="delete(group.id)"
-                                    [disabled]="!('DeleteCustomerGroup' | hasPermission)"
-                                >
-                                    <clr-icon shape="trash" class="is-danger"></clr-icon>
-                                    {{ 'common.delete' | translate }}
-                                </button>
-                            </vdr-dropdown-menu>
-                        </vdr-dropdown>
-                    </td>
-                </tr>
+                ></tr>
             </tbody>
         </table>
     </div>

+ 5 - 2
packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.scss

@@ -9,8 +9,8 @@
         overflow: auto;
         margin-top: 0;
 
-        tr.active {
-            background-color: var(--color-component-bg-200);
+        .active {
+            background-color: var(--clr-global-selection-color);
         }
         &.expanded {
             // Fix for Firefox layout https://github.com/vendure-ecommerce/vendure/issues/531
@@ -18,6 +18,9 @@
         }
     }
 }
+vdr-data-table ::ng-deep table {
+    margin-top: 0;
+}
 .group-members {
     height: 100%;
     width: 0;

+ 53 - 10
packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts

@@ -1,17 +1,31 @@
 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,
     DeletionResult,
     GetCustomerGroups,
+    GetCustomerGroupsQuery,
     GetCustomerGroupWithCustomers,
     GetZones,
+    LogicalOperator,
     ModalService,
     NotificationService,
 } from '@vendure/admin-ui/core';
+import { SortOrder } from '@vendure/common/lib/generated-shop-types';
 import { BehaviorSubject, combineLatest, EMPTY, Observable, of } from 'rxjs';
-import { distinctUntilChanged, map, mapTo, switchMap, tap } from 'rxjs/operators';
+import {
+    debounceTime,
+    distinctUntilChanged,
+    filter,
+    map,
+    mapTo,
+    switchMap,
+    takeUntil,
+    tap,
+} from 'rxjs/operators';
 
 import { AddCustomerToGroupDialogComponent } from '../add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 import { CustomerGroupDetailDialogComponent } from '../customer-group-detail-dialog/customer-group-detail-dialog.component';
@@ -23,9 +37,16 @@ import { CustomerGroupMemberFetchParams } from '../customer-group-member-list/cu
     styleUrls: ['./customer-group-list.component.scss'],
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class CustomerGroupListComponent implements OnInit {
+export class CustomerGroupListComponent
+    extends BaseListComponent<
+        GetCustomerGroupsQuery,
+        GetCustomerGroupsQuery['customerGroups']['items'][number]
+    >
+    implements OnInit
+{
+    searchTerm = new FormControl('');
     activeGroup$: Observable<GetCustomerGroups.Items | undefined>;
-    groups$: Observable<GetCustomerGroups.Items[]>;
+    activeGroupId: string | undefined;
     listIsEmpty$: Observable<boolean>;
     members$: Observable<GetCustomerGroupWithCustomers.Items[]>;
     membersTotal$: Observable<number>;
@@ -42,25 +63,47 @@ export class CustomerGroupListComponent implements OnInit {
         private notificationService: NotificationService,
         private modalService: ModalService,
         public route: ActivatedRoute,
-        private router: Router,
-    ) {}
+        protected router: Router,
+    ) {
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) =>
+                this.dataService.customer.getCustomerGroupList(...args).refetchOnChannelChange(),
+            data => data.customerGroups,
+            (skip, take) => ({
+                options: {
+                    skip,
+                    take,
+                    filter: {
+                        name: { contains: this.searchTerm.value },
+                    },
+                },
+            }),
+        );
+    }
 
     ngOnInit(): void {
-        this.groups$ = this.dataService.customer
-            .getCustomerGroupList()
-            .mapStream(data => data.customerGroups.items);
+        super.ngOnInit();
+        this.searchTerm.valueChanges
+            .pipe(
+                filter(value => 2 < value.length || value.length === 0),
+                debounceTime(250),
+                takeUntil(this.destroy$),
+            )
+            .subscribe(() => this.refresh());
         const activeGroupId$ = this.route.paramMap.pipe(
             map(pm => pm.get('contents')),
             distinctUntilChanged(),
             tap(() => (this.selectedCustomerIds = [])),
         );
-        this.listIsEmpty$ = this.groups$.pipe(map(groups => groups.length === 0));
-        this.activeGroup$ = combineLatest(this.groups$, activeGroupId$).pipe(
+        this.listIsEmpty$ = this.items$.pipe(map(groups => groups.length === 0));
+        this.activeGroup$ = combineLatest(this.items$, activeGroupId$).pipe(
             map(([groups, activeGroupId]) => {
                 if (activeGroupId) {
                     return groups.find(g => g.id === activeGroupId);
                 }
             }),
+            tap(val => (this.activeGroupId = val?.id)),
         );
         const membersResult$ = combineLatest(
             this.activeGroup$,

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -323,6 +323,7 @@
     "registered": "Registrován",
     "remove-customers-from-group-success": "Odebrán: {customerCount, plural, one {1 zákazník} other {{customerCount} zákazníci/zákazníků}} z \"{ groupName }\"",
     "remove-from-group": "Odebrat ze skupiny",
+    "search-by-group-name": "Hledat výraz",
     "search-customers-by-email": "Hledat podle e-mailové adresy",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -323,6 +323,7 @@
     "registered": "Registriert",
     "remove-customers-from-group-success": "{customerCount, plural, one {Kunde} other {{customerCount} Kunden}} aus \"{ groupName }\" entfernt",
     "remove-from-group": "Aus dieser Gruppe entfernen",
+    "search-by-group-name": "Suche nach Begriff",
     "search-customers-by-email": "Suche nach E-Mail-Adresse",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Kunde auswählen",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -323,6 +323,7 @@
     "registered": "Registered",
     "remove-customers-from-group-success": "Removed {customerCount, plural, one {1 customer} other {{customerCount} customers}} from \"{ groupName }\"",
     "remove-from-group": "Remove from this group",
+    "search-by-group-name": "Search by group name",
     "search-customers-by-email": "Search by email address",
     "search-customers-by-email-last-name-postal-code": "Search by email / last name / postal code",
     "select-customer": "Select customer",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -323,6 +323,7 @@
     "registered": "Registrado",
     "remove-customers-from-group-success": "{customerCount, plural, one {1 cliente} other {{customerCount} clientes}} {customerCount, plural, one {eliminado} other {eliminados}} de \"{ groupName }\"",
     "remove-from-group": "Eliminar del grupo",
+    "search-by-group-name": "Buscar por término",
     "search-customers-by-email": "Buscar por correo electrónico",
     "search-customers-by-email-last-name-postal-code": "Buscar por apellido / correo electrónico / Código postal",
     "select-customer": "Seleccionar cliente",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -323,6 +323,7 @@
     "registered": "Inscrit",
     "remove-customers-from-group-success": "Retrait {customerCount, plural, one {d'un client} other {de {customerCount} clients}} de \"{ groupName }\"",
     "remove-from-group": "Retirer de ce groupe",
+    "search-by-group-name": "Chercher le terme",
     "search-customers-by-email": "Chercher par adresse email",
     "search-customers-by-email-last-name-postal-code": "Rechercher par nom / adresse email / code postal",
     "select-customer": "Sélectionner client",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -323,6 +323,7 @@
     "registered": "Registrato",
     "remove-customers-from-group-success": "Ho rimosso {customerCount, plural, one {1 cuclientestomer} other {{customerCount} clienti}} from \"{ groupName }\"",
     "remove-from-group": "Rimuovi da questo gruppo",
+    "search-by-group-name": "Ricerca termine",
     "search-customers-by-email": "Cerca per indirizzo email",
     "search-customers-by-email-last-name-postal-code": "Cerca per cognome / indirizzo email / CAP",
     "select-customer": "Seleziona cliente",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -323,6 +323,7 @@
     "registered": "Zarejestrowany",
     "remove-customers-from-group-success": "",
     "remove-from-group": "",
+    "search-by-group-name": "Szukaj frazy",
     "search-customers-by-email": "Szukaj przez email",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -323,6 +323,7 @@
     "registered": "Registrado",
     "remove-customers-from-group-success": "Excluído {customerCount, plural, one {1 customer} other {{customerCount} customers}} from \"{ groupName }\"",
     "remove-from-group": "Excluir deste grupo",
+    "search-by-group-name": "Pesquisar termo",
     "search-customers-by-email": "Busca por email",
     "search-customers-by-email-last-name-postal-code": "Busca por email / sobrenome / cep",
     "select-customer": "",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -323,6 +323,7 @@
     "registered": "Registado",
     "remove-customers-from-group-success": "{customerCount, plural, one {1 cliente eliminado} other {{customerCount} clientes eliminados}} do grupo \"{ groupName }\"",
     "remove-from-group": "Eliminar deste grupo",
+    "search-by-group-name": "Pesquisar termo",
     "search-customers-by-email": "Pesquisar por email",
     "search-customers-by-email-last-name-postal-code": "Pesquisar pelo apelido / email / código postal",
     "select-customer": "Seleccione o cliente",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -323,6 +323,7 @@
     "registered": "Зарегистрировано",
     "remove-customers-from-group-success": "Удален {customerCount, plural, one {1 клиент} other {{customerCount} клиентов}} из \"{ groupName }\"",
     "remove-from-group": "Удалить из этой группы",
+    "search-by-group-name": "Искать по фразе",
     "search-customers-by-email": "Поиск по адресу электронной почты",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Выберите клиента",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -323,6 +323,7 @@
     "registered": "Зареєстровано",
     "remove-customers-from-group-success": "Видалено {customerCount, plural, one {1 клієнт} other {{customerCount} клієнтів}} из \"{ groupName }\"",
     "remove-from-group": "Вилучити з цієї групи",
+    "search-by-group-name": "Шукати по фразі",
     "search-customers-by-email": "Пошук за адресою електронної пошти",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Виберіть клієнта",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -323,6 +323,7 @@
     "registered": "已注册",
     "remove-customers-from-group-success": "成功从分组\"{ groupName }\"中移除{customerCount}个客户",
     "remove-from-group": "从分组中移除",
+    "search-by-group-name": "输入搜索条目",
     "search-customers-by-email": "输入要搜索的客户邮件地址",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "选择客户",

+ 1 - 0
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -323,6 +323,7 @@
     "registered": "已注册",
     "remove-customers-from-group-success": "",
     "remove-from-group": "",
+    "search-by-group-name": "輸入搜索條目",
     "search-customers-by-email": "輸入要搜索的客户電郵地址",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",