From 0e054967c2d0baf6d4f878f9f91717c096dd97a3 Mon Sep 17 00:00:00 2001 From: Michael Bromley Date: Thu, 24 Aug 2023 15:47:08 +0200 Subject: [PATCH] fix(admin-ui): Correct handling of ID filters in data tables --- .../collection-list.component.ts | 1 + .../facet-list/facet-list.component.ts | 1 + .../product-list/product-list.component.ts | 7 +-- .../product-variant-list.component.ts | 7 +-- .../stock-location-list.component.ts | 7 +-- .../data-table-filter-collection.ts | 60 +++++++++++++------ .../providers/data-table/data-table-filter.ts | 21 +++++++ .../data-table-filter-label.component.html | 7 +++ .../data-table-filters.component.html | 11 ++++ .../data-table-filters.component.ts | 22 ++++++- .../customer-group-list.component.ts | 1 + .../customer-list/customer-list.component.ts | 1 + .../promotion-list.component.ts | 1 + .../order-list/order-list.component.ts | 1 + .../administrator-list.component.ts | 1 + .../channel-list/channel-list.component.ts | 1 + .../country-list/country-list.component.ts | 3 +- .../payment-method-list.component.ts | 1 + .../role-list/role-list.component.ts | 1 + .../seller-list/seller-list.component.ts | 2 +- .../shipping-method-list.component.ts | 1 + .../tax-category-list.component.ts | 1 + .../tax-rate-list/tax-rate-list.component.ts | 1 + .../zone-list/zone-list.component.ts | 1 + 24 files changed, 123 insertions(+), 38 deletions(-) diff --git a/packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts b/packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts index 620604e466..3c3b55b6ba 100644 --- a/packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts b/packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts index 120fe34abf..97948c0750 100644 --- a/packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts +++ b/packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts @@ -38,6 +38,7 @@ export class FacetListComponent readonly customFields = this.getCustomFieldConfig('Facet'); readonly filters = this.createFilterCollection() + .addIdFilter() .addDateFilters() .addFilter({ name: 'visibility', diff --git a/packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts b/packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts index 0a50304b9f..030a942d59 100644 --- a/packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts +++ b/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' }, diff --git a/packages/admin-ui/src/lib/catalog/src/components/product-variant-list/product-variant-list.component.ts b/packages/admin-ui/src/lib/catalog/src/components/product-variant-list/product-variant-list.component.ts index 09bc7c4fb6..395a10dd06 100644 --- a/packages/admin-ui/src/lib/catalog/src/components/product-variant-list/product-variant-list.component.ts +++ b/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' }, diff --git a/packages/admin-ui/src/lib/catalog/src/components/stock-location-list/stock-location-list.component.ts b/packages/admin-ui/src/lib/catalog/src/components/stock-location-list/stock-location-list.component.ts index 33b97ce823..e5f7ba3367 100644 --- a/packages/admin-ui/src/lib/catalog/src/components/stock-location-list/stock-location-list.component.ts +++ b/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' }, diff --git a/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts b/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts index 057b2e5500..f305416fac 100644 --- a/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter-collection.ts +++ b/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 { + return this.filter.type.kind === 'id'; + } + isText(): this is FilterWithValue { return this.filter.type.kind === 'text'; } @@ -112,6 +118,20 @@ export class DataTableFilterCollection = return this; } + addIdFilter(): FilterInput extends { + id?: IdOperators | null; + } + ? DataTableFilterCollection + : 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 = return this; } - serializeValue( + serialize(): string { + return this.#activeFilters + .map( + (filterWithValue, i) => + `${filterWithValue.filter.name}:${this.serializeValue(filterWithValue)}`, + ) + .join(';'); + } + + private serializeValue( filterWithValue: FilterWithValue, ): string | undefined { - const valueAsType = >( - _filter: T, - _value: DataTableFilterValue, - ): T extends DataTableFilter ? DataTableFilterValue : 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 = } } - deserializeValue(filter: DataTableFilter, value: string): DataTableFilterValue { + private deserializeValue( + filter: DataTableFilter, + value: string, + ): DataTableFilterValue { 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 = } } - private serialize(): string { - return this.#activeFilters - .map( - (filterWithValue, i) => - `${filterWithValue.filter.name}:${this.serializeValue(filterWithValue)}`, - ) - .join(';'); - } - private onActivateFilter(filter: DataTableFilter, value: DataTableFilterValue) { this.#activeFilters.push(this.createFacetWithValue(filter, value)); this.#valueChanges$.next(this.#activeFilters); diff --git a/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter.ts b/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter.ts index 756adda635..ff78272b73 100644 --- a/packages/admin-ui/src/lib/core/src/providers/data-table/data-table-filter.ts +++ b/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 { + return this.type.kind === 'id'; + } + isText(): this is DataTableFilter { return this.type.kind === 'text'; } diff --git a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html b/packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html index ee7057afca..f8548734b2 100644 --- a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html +++ b/packages/admin-ui/src/lib/core/src/shared/components/data-table-filter-label/data-table-filter-label.component.html @@ -3,6 +3,13 @@ {{ filterWithValue.value?.join(', ') }} + + {{ 'common.operator-eq' | translate }} + {{ + 'common.operator-not-eq' | translate + }} + "{{ filterWithValue.value?.term }}" + {{ 'common.operator-contains' | translate diff --git a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.html b/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.html index f4b0f9d864..4f7a0080a6 100644 --- a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.html +++ b/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.html @@ -64,6 +64,17 @@ +
+
+
+ +
+ +
+
diff --git a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.ts b/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.ts index fd0a5b4a66..c19840d201 100644 --- a/packages/admin-ui/src/lib/core/src/shared/components/data-table-filters/data-table-filters.component.ts +++ b/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); diff --git a/packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts b/packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts index 9ad357fd1a..f7282e63ad 100644 --- a/packages/admin-ui/src/lib/customer/src/components/customer-group-list/customer-group-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts b/packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts index d99c201b7f..9d707f3d79 100644 --- a/packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts b/packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts index ad26bc76a8..58bb5451bf 100644 --- a/packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts +++ b/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([ { diff --git a/packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts b/packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts index 52ae42249d..f64fc7bc37 100644 --- a/packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts index 522a8e846c..c7361989f0 100644 --- a/packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts index 80c9438c0f..ca6c374879 100644 --- a/packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts index b0c111f69c..56d8f65dae 100644 --- a/packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts +++ b/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 { readonly customFields = this.getCustomFieldConfig('Region'); readonly filters = this.createFilterCollection() + .addIdFilter() .addDateFilters() .addFilter({ name: 'name', @@ -40,7 +41,7 @@ export class CountryListComponent extends TypedBaseListComponent { readonly customFields = this.getCustomFieldConfig('PaymentMethod'); readonly filters = this.createFilterCollection() + .addIdFilter() .addDateFilters() .addFilter({ name: 'name', diff --git a/packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts index f8f3bbd284..d522b7cfcd 100644 --- a/packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts index 4892dabdb2..c4b127501d 100644 --- a/packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts +++ b/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' }, diff --git a/packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts index d6cd3b00d9..5bfcc2dc5a 100644 --- a/packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts +++ b/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', diff --git a/packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts index 18313ad686..9d4f0cea7f 100644 --- a/packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts +++ b/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' }, diff --git a/packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts index 4c6f58d908..5cd9f4cdb9 100644 --- a/packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts +++ b/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 { readonly customFields = this.getCustomFieldConfig('TaxRate'); readonly filters = this.createFilterCollection() + .addIdFilter() .addDateFilters() .addFilter({ name: 'name', diff --git a/packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.ts b/packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.ts index e715fe624a..63f2e1c4bc 100644 --- a/packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.ts +++ b/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',