Browse Source

fix(admin-ui): Correct handling of ID filters in data tables

Michael Bromley 2 years ago
parent
commit
52ddd9696b
24 changed files with 123 additions and 38 deletions
  1. 1 0
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts
  2. 1 0
      packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts
  3. 1 6
      packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts
  4. 1 6
      packages/admin-ui/src/lib/catalog/src/components/product-variant-list/product-variant-list.component.ts
  5. 1 6
      packages/admin-ui/src/lib/catalog/src/components/stock-location-list/stock-location-list.component.ts
  6. 43 17
      packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts
  7. 21 0
      packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter.ts
  8. 7 0
      packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html
  9. 11 0
      packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.html
  10. 21 1
      packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.ts
  11. 1 0
      packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts
  12. 1 0
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts
  13. 1 0
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts
  14. 1 0
      packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts
  15. 1 0
      packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts
  16. 1 0
      packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts
  17. 2 1
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts
  18. 1 0
      packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.ts
  19. 1 0
      packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts
  20. 1 1
      packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts
  21. 1 0
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts
  22. 1 0
      packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts
  23. 1 0
      packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts
  24. 1 0
      packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.ts

+ 1 - 0
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts

@@ -30,6 +30,7 @@ export class CollectionListComponent
     expandedIds: string[] = [];
     readonly customFields = this.getCustomFieldConfig('Collection');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'slug',

+ 1 - 0
packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts

@@ -37,6 +37,7 @@ export class FacetListComponent
 
     readonly customFields = this.getCustomFieldConfig('Facet');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'visibility',

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

@@ -25,14 +25,9 @@ export class ProductListComponent
     pendingSearchIndexUpdates = 0;
     readonly customFields = this.getCustomFieldConfig('Product');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilters([
-            {
-                name: 'id',
-                type: { kind: 'text' },
-                label: _('common.id'),
-                filterField: 'id',
-            },
             {
                 name: 'enabled',
                 type: { kind: 'boolean' },

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

@@ -19,6 +19,7 @@ export class ProductVariantListComponent
     @Input() hideLanguageSelect = false;
     readonly customFields = this.getCustomFieldConfig('ProductVariant');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilters([
             {
@@ -27,12 +28,6 @@ export class ProductVariantListComponent
                 label: _('common.name'),
                 filterField: 'name',
             },
-            {
-                name: 'id',
-                type: { kind: 'text' },
-                label: _('common.id'),
-                filterField: 'id',
-            },
             {
                 name: 'enabled',
                 type: { kind: 'boolean' },

+ 1 - 6
packages/admin-ui/src/lib/catalog/src/components/stock-location-list/stock-location-list.component.ts

@@ -33,14 +33,9 @@ export class StockLocationListComponent
 {
     readonly customFields = this.getCustomFieldConfig('StockLocation');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilters([
-            {
-                name: 'id',
-                type: { kind: 'text' },
-                label: _('common.id'),
-                filterField: 'id',
-            },
             {
                 name: 'enabled',
                 type: { kind: 'text' },

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

@@ -2,11 +2,12 @@ import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import { CustomFieldType } from '@vendure/common/lib/shared-types';
 import { assertNever } from '@vendure/common/lib/shared-utils';
-import { Subject } from 'rxjs';
 import extend from 'just-extend';
+import { Subject } from 'rxjs';
 import {
     CustomFieldConfig,
     DateOperators,
+    IdOperators,
     NumberOperators,
     StringOperators,
 } from '../../common/generated-types';
@@ -15,6 +16,7 @@ import {
     DataTableFilterBooleanType,
     DataTableFilterCustomType,
     DataTableFilterDateRangeType,
+    DataTableFilterIDType,
     DataTableFilterNumberType,
     DataTableFilterOptions,
     DataTableFilterSelectType,
@@ -46,6 +48,10 @@ export class FilterWithValue<Type extends DataTableFilterType = DataTableFilterT
         }
     }
 
+    isId(): this is FilterWithValue<DataTableFilterIDType> {
+        return this.filter.type.kind === 'id';
+    }
+
     isText(): this is FilterWithValue<DataTableFilterTextType> {
         return this.filter.type.kind === 'text';
     }
@@ -112,6 +118,20 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         return this;
     }
 
+    addIdFilter(): FilterInput extends {
+        id?: IdOperators | null;
+    }
+        ? DataTableFilterCollection<FilterInput>
+        : never {
+        this.addFilter({
+            name: 'id',
+            type: { kind: 'id' },
+            label: _('common.id'),
+            filterField: 'id',
+        });
+        return this as any;
+    }
+
     addDateFilters(): FilterInput extends {
         createdAt?: DateOperators | null;
         updatedAt?: DateOperators | null;
@@ -219,14 +239,22 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         return this;
     }
 
-    serializeValue<Type extends DataTableFilterType>(
+    serialize(): string {
+        return this.#activeFilters
+            .map(
+                (filterWithValue, i) =>
+                    `${filterWithValue.filter.name}:${this.serializeValue(filterWithValue)}`,
+            )
+            .join(';');
+    }
+
+    private serializeValue<Type extends DataTableFilterType>(
         filterWithValue: FilterWithValue<Type>,
     ): string | undefined {
-        const valueAsType = <T extends DataTableFilter<any, any>>(
-            _filter: T,
-            _value: DataTableFilterValue<any>,
-        ): T extends DataTableFilter<any, infer R> ? DataTableFilterValue<R> : any => _value;
-
+        if (filterWithValue.isId()) {
+            const val = filterWithValue.value;
+            return `${val?.operator},${val?.term}`;
+        }
         if (filterWithValue.isText()) {
             const val = filterWithValue.value;
             return `${val?.operator},${val?.term}`;
@@ -249,8 +277,15 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         }
     }
 
-    deserializeValue(filter: DataTableFilter, value: string): DataTableFilterValue<DataTableFilterType> {
+    private deserializeValue(
+        filter: DataTableFilter,
+        value: string,
+    ): DataTableFilterValue<DataTableFilterType> {
         switch (filter.type.kind) {
+            case 'id': {
+                const [operator, term] = value.split(',') as [keyof StringOperators, string];
+                return { operator, term };
+            }
             case 'text': {
                 const [operator, term] = value.split(',') as [keyof StringOperators, string];
                 return { operator, term };
@@ -275,15 +310,6 @@ export class DataTableFilterCollection<FilterInput extends Record<string, any> =
         }
     }
 
-    private serialize(): string {
-        return this.#activeFilters
-            .map(
-                (filterWithValue, i) =>
-                    `${filterWithValue.filter.name}:${this.serializeValue(filterWithValue)}`,
-            )
-            .join(';');
-    }
-
     private onActivateFilter(filter: DataTableFilter<any, any>, value: DataTableFilterValue<any>) {
         this.#activeFilters.push(this.createFacetWithValue(filter, value));
         this.#valueChanges$.next(this.#activeFilters);

+ 21 - 0
packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter.ts

@@ -5,10 +5,15 @@ import { FormInputComponent } from '../../common/component-registry-types';
 import {
     BooleanOperators,
     DateOperators,
+    IdOperators,
     NumberOperators,
     StringOperators,
 } from '../../common/generated-types';
 
+export interface DataTableFilterIDType {
+    kind: 'id';
+}
+
 export interface DataTableFilterTextType {
     kind: 'text';
     placeholder?: string;
@@ -41,6 +46,13 @@ export interface DataTableFilterCustomType {
 }
 
 export type KindValueMap = {
+    id: {
+        raw: {
+            operator: keyof IdOperators;
+            term: string;
+        };
+        input: IdOperators;
+    };
     text: {
         raw: {
             operator: keyof StringOperators;
@@ -55,6 +67,7 @@ export type KindValueMap = {
     custom: { raw: any; input: any };
 };
 export type DataTableFilterType =
+    | DataTableFilterIDType
     | DataTableFilterTextType
     | DataTableFilterSelectType
     | DataTableFilterBooleanType
@@ -137,6 +150,10 @@ export class DataTableFilter<
                 return {
                     [value.operator]: value.term,
                 };
+            case 'id':
+                return {
+                    [value.operator]: value.term,
+                };
             case 'custom': {
                 return value;
             }
@@ -164,6 +181,10 @@ export class DataTableFilter<
         }
     }
 
+    isId(): this is DataTableFilter<FilterInput, DataTableFilterIDType> {
+        return this.type.kind === 'id';
+    }
+
     isText(): this is DataTableFilter<FilterInput, DataTableFilterTextType> {
         return this.type.kind === 'text';
     }

+ 7 - 0
packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html

@@ -3,6 +3,13 @@
     <ng-container *ngIf="filterWithValue.isSelect()">
         {{ filterWithValue.value?.join(', ') }}
     </ng-container>
+    <ng-container *ngIf="filterWithValue.isId()">
+        <span *ngIf="filterWithValue.value?.operator === 'eq'">{{ 'common.operator-eq' | translate }}</span>
+        <span *ngIf="filterWithValue.value?.operator === 'notEq'">{{
+            'common.operator-not-eq' | translate
+        }}</span>
+        <span> "{{ filterWithValue.value?.term }}"</span>
+    </ng-container>
     <ng-container *ngIf="filterWithValue.isText()">
         <span *ngIf="filterWithValue.value?.operator === 'contains'">{{
             'common.operator-contains' | translate

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

@@ -64,6 +64,17 @@
                             <input type="text" formControlName="term" />
                         </div>
                     </div>
+                    <div *ngSwitchCase="'id'">
+                        <div [formGroup]="formControl">
+                            <div>
+                                <select name="options" formControlName="operator" class="mb-1">
+                                    <option value="eq">{{ 'common.operator-eq' | translate }}</option>
+                                    <option value="notEq">{{ 'common.operator-not-eq' | translate }}</option>
+                                </select>
+                            </div>
+                            <input type="text" formControlName="term" />
+                        </div>
+                    </div>
                     <div *ngSwitchCase="'number'">
                         <div [formGroup]="formControl">
                             <div>

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

@@ -11,7 +11,7 @@ import {
 import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms';
 import { assertNever } from '@vendure/common/lib/shared-utils';
 import { FormInputComponent } from '../../../common/component-registry-types';
-import { DateOperators, LanguageCode } from '../../../common/generated-types';
+import { DateOperators } from '../../../common/generated-types';
 import { DataTableFilter, KindValueMap } from '../../../providers/data-table/data-table-filter';
 import {
     DataTableFilterCollection,
@@ -71,6 +71,20 @@ export class DataTableFiltersComponent implements AfterViewInit {
 
     selectFilter(filter: DataTableFilter, value?: any) {
         this.selectedFilter = filter;
+        if (filter.isId()) {
+            this.formControl = new FormGroup(
+                {
+                    operator: new FormControl(value?.operator ?? 'eq'),
+                    term: new FormControl(value?.term ?? ''),
+                },
+                control => {
+                    if (!control.value.term) {
+                        return { noSelection: true };
+                    }
+                    return null;
+                },
+            );
+        }
         if (filter.isText()) {
             this.formControl = new FormGroup(
                 {
@@ -182,6 +196,12 @@ export class DataTableFiltersComponent implements AfterViewInit {
                     term: this.formControl.value.term,
                 } as KindValueMap[typeof type.kind]['raw'];
                 break;
+            case 'id':
+                value = {
+                    operator: this.formControl.value.operator,
+                    term: this.formControl.value.term,
+                } as KindValueMap[typeof type.kind]['raw'];
+                break;
             case 'custom':
                 value = this.customComponent?.instance.formControl.value;
                 this.formControl.setValue(value);

+ 1 - 0
packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts

@@ -54,6 +54,7 @@ export class CustomerGroupListComponent
         filterTerm: '',
     });
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',

+ 1 - 0
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts

@@ -38,6 +38,7 @@ export class CustomerListComponent
     implements OnInit
 {
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'firstName',

+ 1 - 0
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts

@@ -34,6 +34,7 @@ export class PromotionListComponent
 {
     readonly customFields = this.getCustomFieldConfig('Promotion');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilters([
             {

+ 1 - 0
packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts

@@ -27,6 +27,7 @@ export class OrderListComponent
     readonly OrderType = OrderType;
     readonly customFields = this.getCustomFieldConfig('Order');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'active',

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts

@@ -50,6 +50,7 @@ export class AdministratorListComponent extends TypedBaseListComponent<
 > {
     readonly customFields = this.getCustomFieldConfig('Administrator');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'firstName',

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts

@@ -28,6 +28,7 @@ export class ChannelListComponent
 {
     readonly customFields = this.getCustomFieldConfig('Channel');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'code',

+ 2 - 1
packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts

@@ -32,6 +32,7 @@ export const GET_COUNTRY_LIST = gql`
 export class CountryListComponent extends TypedBaseListComponent<typeof GetCountryListDocument, 'countries'> {
     readonly customFields = this.getCustomFieldConfig('Region');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',
@@ -40,7 +41,7 @@ export class CountryListComponent extends TypedBaseListComponent<typeof GetCount
             filterField: 'name',
         })
         .addFilter({
-            name: 'cpde',
+            name: 'code',
             type: { kind: 'text' },
             label: _('common.code'),
             filterField: 'code',

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.ts

@@ -35,6 +35,7 @@ export class PaymentMethodListComponent extends TypedBaseListComponent<
 > {
     readonly customFields = this.getCustomFieldConfig('PaymentMethod');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts

@@ -36,6 +36,7 @@ export class RoleListComponent
     readonly initialLimit = 3;
     displayLimit: { [id: string]: number } = {};
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'code',

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

@@ -32,8 +32,8 @@ export class SellerListComponent
 {
     readonly customFields = this.getCustomFieldConfig('Seller');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
-
         .addFilter({
             name: 'name',
             type: { kind: 'text' },

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

@@ -35,6 +35,7 @@ export class ShippingMethodListComponent
 {
     readonly customFields = this.getCustomFieldConfig('ShippingMethod');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',

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

@@ -31,6 +31,7 @@ export class TaxCategoryListComponent extends TypedBaseListComponent<
 > {
     readonly customFields = this.serverConfigService.getCustomFieldsFor('TaxCategory');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },

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

@@ -24,6 +24,7 @@ export const GET_TAX_RATE_LIST = gql`
 export class TaxRateListComponent extends TypedBaseListComponent<typeof GetTaxRateListDocument, 'taxRates'> {
     readonly customFields = this.getCustomFieldConfig('TaxRate');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.ts

@@ -51,6 +51,7 @@ export class ZoneListComponent
     @ViewChild(ZoneMemberListComponent) zoneMemberList: ZoneMemberListComponent;
     readonly customFields = this.serverConfigService.getCustomFieldsFor('Zone');
     readonly filters = this.createFilterCollection()
+        .addIdFilter()
         .addDateFilters()
         .addFilter({
             name: 'name',