Przeglądaj źródła

refactor(admin-ui): Improve handling & display of FacetValues

Michael Bromley 7 lat temu
rodzic
commit
5ce1c4a83b
19 zmienionych plików z 300 dodań i 57 usunięć
  1. 4 1
      admin-ui/src/app/catalog/components/apply-facet-dialog/apply-facet-dialog.component.html
  2. 3 2
      admin-ui/src/app/catalog/components/apply-facet-dialog/apply-facet-dialog.component.ts
  3. 2 2
      admin-ui/src/app/catalog/components/facet-value-selector/facet-value-selector.component.html
  4. 12 20
      admin-ui/src/app/catalog/components/facet-value-selector/facet-value-selector.component.ts
  5. 1 0
      admin-ui/src/app/catalog/components/product-detail/product-detail.component.html
  6. 66 23
      admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts
  7. 10 3
      admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.html
  8. 80 3
      admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.ts
  9. 71 0
      admin-ui/src/app/common/utilities/flatten-facet-values.spec.ts
  10. 8 0
      admin-ui/src/app/common/utilities/flatten-facet-values.ts
  11. 4 0
      admin-ui/src/app/data/definitions/facet-definitions.ts
  12. 4 0
      admin-ui/src/app/data/definitions/product-definitions.ts
  13. 3 1
      admin-ui/src/app/data/providers/product-data.service.ts
  14. 3 1
      admin-ui/src/app/shared/components/chip/chip.component.html
  15. 3 1
      admin-ui/src/app/shared/components/chip/chip.component.scss
  16. 4 0
      admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.html
  17. 7 0
      admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.scss
  18. 13 0
      admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.ts
  19. 2 0
      admin-ui/src/app/shared/shared.module.ts

+ 4 - 1
admin-ui/src/app/catalog/components/apply-facet-dialog/apply-facet-dialog.component.html

@@ -1,6 +1,9 @@
 <ng-template vdrDialogTitle>{{ 'catalog.apply-facets' | translate }}</ng-template>
 
-<vdr-facet-value-selector (selectedValuesChange)="selectedValues = $event"></vdr-facet-value-selector>
+<vdr-facet-value-selector
+    [facets]="facets"
+    (selectedValuesChange)="selectedValues = $event"
+></vdr-facet-value-selector>
 
 <ng-template vdrDialogButtons>
     <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>

+ 3 - 2
admin-ui/src/app/catalog/components/apply-facet-dialog/apply-facet-dialog.component.ts

@@ -1,5 +1,5 @@
 import { ChangeDetectionStrategy, Component } from '@angular/core';
-import { FacetValue, ProductOptionGroup } from 'shared/generated-types';
+import { FacetValue, FacetWithValues } from 'shared/generated-types';
 
 import { Dialog } from '../../../shared/providers/modal/modal.service';
 
@@ -10,9 +10,10 @@ import { Dialog } from '../../../shared/providers/modal/modal.service';
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class ApplyFacetDialogComponent implements Dialog<FacetValue[]> {
-    existingOptionGroups: Array<Partial<ProductOptionGroup>>;
     resolveWith: (result?: FacetValue[]) => void;
     selectedValues: FacetValue[] = [];
+    // Provided by caller
+    facets: FacetWithValues.Fragment[];
 
     selectValues() {
         this.resolveWith(this.selectedValues);

+ 2 - 2
admin-ui/src/app/catalog/components/facet-value-selector/facet-value-selector.component.html

@@ -1,6 +1,6 @@
 <ng-select
-    [items]="facetValues$ | async"
-    [addTag]="true"
+    [items]="facetValues"
+    [addTag]="false"
     [hideSelected]="true"
     groupBy="facetName"
     bindValue="value"

+ 12 - 20
admin-ui/src/app/catalog/components/facet-value-selector/facet-value-selector.component.ts

@@ -1,7 +1,7 @@
-import { ChangeDetectionStrategy, Component, EventEmitter, OnInit, Output } from '@angular/core';
-import { Observable } from 'rxjs';
-import { FacetValue } from 'shared/generated-types';
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FacetValue, FacetWithValues } from 'shared/generated-types';
 
+import { flattenFacetValues } from '../../../common/utilities/flatten-facet-values';
 import { DataService } from '../../../data/providers/data.service';
 
 export type FacetValueSeletorItem = {
@@ -19,27 +19,19 @@ export type FacetValueSeletorItem = {
 })
 export class FacetValueSelectorComponent implements OnInit {
     @Output() selectedValuesChange = new EventEmitter<FacetValue.Fragment[]>();
+    @Input() facets: FacetWithValues.Fragment[];
 
-    facetValues$: Observable<FacetValueSeletorItem[]>;
+    facetValues: FacetValueSeletorItem[] = [];
     constructor(private dataService: DataService) {}
 
     ngOnInit() {
-        this.facetValues$ = this.dataService.facet.getFacets(9999999, 0).mapSingle(result => {
-            return result.facets.items.reduce(
-                (flattened, facet) => {
-                    return flattened.concat(
-                        facet.values.map(value => {
-                            return {
-                                name: value.name,
-                                facetName: facet.name,
-                                id: value.id,
-                                value,
-                            };
-                        }),
-                    );
-                },
-                [] as FacetValueSeletorItem[],
-            );
+        this.facetValues = flattenFacetValues(this.facets).map(value => {
+            return {
+                name: value.name,
+                facetName: value.facet.name,
+                id: value.id,
+                value,
+            };
         });
     }
 

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

@@ -101,6 +101,7 @@
 
                         <vdr-product-variants-list
                             [variants]="variants$ | async"
+                            [facets]="facets$ | async"
                             [productVariantsFormArray]="productForm.get('variants')"
                             [taxCategories]="taxCategories$ | async"
                             #productVariantsList

+ 66 - 23
admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts

@@ -1,11 +1,12 @@
 import { Location } from '@angular/common';
-import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, EMPTY, forkJoin, Observable } from 'rxjs';
-import { map, mergeMap, take } from 'rxjs/operators';
+import { BehaviorSubject, combineLatest, forkJoin, Observable } from 'rxjs';
+import { map, mergeMap, skip, take, withLatestFrom } from 'rxjs/operators';
 import {
     CreateProductInput,
+    FacetWithValues,
     LanguageCode,
     ProductWithVariants,
     TaxCategory,
@@ -26,6 +27,15 @@ import { ModalService } from '../../../shared/providers/modal/modal.service';
 import { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';
 
 export type TabName = 'details' | 'variants';
+export interface VariantFormValue {
+    sku: string;
+    name: string;
+    price: number;
+    priceIncludesTax: boolean;
+    priceWithTax: number;
+    taxCategoryId: string;
+    facetValueIds: string[];
+}
 
 @Component({
     selector: 'vdr-product-detail',
@@ -43,6 +53,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
     customVariantFields: CustomFieldConfig[];
     productForm: FormGroup;
     assetChanges: { assetIds?: string[]; featuredAssetId?: string } = {};
+    facets$ = new BehaviorSubject<FacetWithValues.Fragment[]>([]);
 
     constructor(
         route: ActivatedRoute,
@@ -53,6 +64,7 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
         private modalService: ModalService,
         private notificationService: NotificationService,
         private location: Location,
+        private changeDetector: ChangeDetectorRef,
     ) {
         super(route, router, serverConfigService);
         this.customFields = this.getCustomFieldConfig('Product');
@@ -118,22 +130,44 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
      * Opens a dialog to select FacetValues to apply to the select ProductVariants.
      */
     selectFacetValue(selectedVariantIds: string[]) {
-        this.modalService
-            .fromComponent(ApplyFacetDialogComponent, { size: 'md' })
+        this.dataService.facet
+            .getFacets(9999999, 0)
+            .mapSingle(data => data.facets.items)
+            .subscribe(items => this.facets$.next(items));
+
+        this.facets$
             .pipe(
+                skip(1),
+                take(1),
+                mergeMap(facets =>
+                    this.modalService.fromComponent(ApplyFacetDialogComponent, {
+                        size: 'md',
+                        locals: { facets },
+                    }),
+                ),
                 map(facetValues => facetValues && facetValues.map(v => v.id)),
-                mergeMap(facetValueIds => {
-                    if (facetValueIds) {
-                        return this.dataService.product.applyFacetValuesToProductVariants(
-                            facetValueIds,
-                            selectedVariantIds,
+                withLatestFrom(this.variants$),
+            )
+            .subscribe(([facetValueIds, variants]) => {
+                if (facetValueIds) {
+                    for (const variantId of selectedVariantIds) {
+                        const index = variants.findIndex(v => v.id === variantId);
+                        const variant = variants[index];
+                        const existingFacetValueIds = variant ? variant.facetValues.map(fv => fv.id) : [];
+                        const uniqueFacetValueIds = Array.from(
+                            new Set([...existingFacetValueIds, ...facetValueIds]),
                         );
-                    } else {
-                        return EMPTY;
+                        const variantFormGroup = this.productForm.get(['variants', index]);
+                        if (variantFormGroup) {
+                            variantFormGroup.patchValue({
+                                facetValueIds: uniqueFacetValueIds,
+                            });
+                            variantFormGroup.markAsDirty();
+                        }
                     }
-                }),
-            )
-            .subscribe();
+                    this.changeDetector.markForCheck();
+                }
+            });
     }
 
     create() {
@@ -250,21 +284,28 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
             const variantsFormArray = this.productForm.get('variants') as FormArray;
             product.variants.forEach((variant, i) => {
                 const variantTranslation = variant.translations.find(t => t.languageCode === languageCode);
-
-                const group = {
+                const facetValueIds = variant.facetValues.map(fv => fv.id);
+                const group: VariantFormValue = {
                     sku: variant.sku,
                     name: variantTranslation ? variantTranslation.name : '',
                     price: variant.price,
                     priceIncludesTax: variant.priceIncludesTax,
                     priceWithTax: variant.priceWithTax,
                     taxCategoryId: variant.taxCategory.id,
+                    facetValueIds,
                 };
 
                 const existing = variantsFormArray.at(i);
                 if (existing) {
                     existing.setValue(group);
                 } else {
-                    variantsFormArray.insert(i, this.formBuilder.group(group));
+                    variantsFormArray.insert(
+                        i,
+                        this.formBuilder.group({
+                            ...group,
+                            facetValueIds: this.formBuilder.control(facetValueIds),
+                        }),
+                    );
                 }
             });
         }
@@ -314,14 +355,16 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
         }
         return dirtyVariants
             .map((variant, i) => {
-                const updated = createUpdatedTranslatable({
+                const formValue: VariantFormValue = dirtyVariantValues[i];
+                const result: UpdateProductVariantInput = createUpdatedTranslatable({
                     translatable: variant,
-                    updatedFields: dirtyVariantValues[i],
+                    updatedFields: formValue,
                     customFieldConfig: this.customVariantFields,
                     languageCode,
-                }) as UpdateProductVariantInput;
-                updated.taxCategoryId = dirtyVariantValues[i].taxCategoryId;
-                return updated;
+                });
+                result.taxCategoryId = formValue.taxCategoryId;
+                result.facetValueIds = formValue.facetValueIds;
+                return result;
             })
             .filter(notNullOrUndefined);
     }

+ 10 - 3
admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.html

@@ -24,9 +24,16 @@
             </div>
             <div class="flex-spacer"></div>
             <div class="facets">
-                <div *ngIf="variant.facetValues.length">{{ 'catalog.facets' | translate }}:</div>
-                <div *ngIf="!variant.facetValues.length">{{ 'catalog.no-facets' | translate }}</div>
-                <vdr-chip *ngFor="let facetValue of variant.facetValues">{{ facetValue.name }}</vdr-chip>
+                <vdr-facet-value-chip
+                    *ngFor="let facetValue of existingFacetValues(i)"
+                    [facetValue]="facetValue"
+                    (remove)="removeFacetValue(i, facetValue.id)"
+                ></vdr-facet-value-chip>
+                <vdr-facet-value-chip
+                    *ngFor="let facetValue of pendingFacetValues(i)"
+                    [facetValue]="facetValue"
+                    (remove)="removeFacetValue(i, facetValue.id)"
+                ></vdr-facet-value-chip>
             </div>
         </div>
         <div class="card-block">

+ 80 - 3
admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.ts

@@ -1,6 +1,20 @@
-import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
+import {
+    ChangeDetectionStrategy,
+    ChangeDetectorRef,
+    Component,
+    Input,
+    OnChanges,
+    OnDestroy,
+    OnInit,
+    SimpleChanges,
+} from '@angular/core';
 import { FormArray } from '@angular/forms';
-import { ProductWithVariants, TaxCategory } from 'shared/generated-types';
+import { Subscription } from 'rxjs';
+import { FacetValue, FacetWithValues, ProductWithVariants, TaxCategory } from 'shared/generated-types';
+import { notNullOrUndefined } from 'shared/shared-utils';
+
+import { flattenFacetValues } from '../../../common/utilities/flatten-facet-values';
+import { VariantFormValue } from '../product-detail/product-detail.component';
 
 @Component({
     selector: 'vdr-product-variants-list',
@@ -8,11 +22,34 @@ import { ProductWithVariants, TaxCategory } from 'shared/generated-types';
     styleUrls: ['./product-variants-list.component.scss'],
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class ProductVariantsListComponent {
+export class ProductVariantsListComponent implements OnChanges, OnInit, OnDestroy {
     @Input('productVariantsFormArray') formArray: FormArray;
     @Input() variants: ProductWithVariants.Variants[];
     @Input() taxCategories: TaxCategory[];
+    @Input() facets: FacetWithValues.Fragment[];
     selectedVariantIds: string[] = [];
+    private facetValues: FacetValue.Fragment[];
+    private formSubscription: Subscription;
+
+    constructor(private changeDetector: ChangeDetectorRef) {}
+
+    ngOnInit() {
+        this.formSubscription = this.formArray.valueChanges.subscribe(() =>
+            this.changeDetector.markForCheck(),
+        );
+    }
+
+    ngOnChanges(changes: SimpleChanges) {
+        if ('facets' in changes) {
+            this.facetValues = flattenFacetValues(this.facets);
+        }
+    }
+
+    ngOnDestroy() {
+        if (this.formSubscription) {
+            this.formSubscription.unsubscribe();
+        }
+    }
 
     areAllSelected(): boolean {
         return !!this.variants && this.selectedVariantIds.length === this.variants.length;
@@ -35,7 +72,47 @@ export class ProductVariantsListComponent {
         }
     }
 
+    pendingFacetValues(index: number) {
+        if (this.facets) {
+            const formFacetValueIds = this.getFacetValueIds(index);
+            const variantFacetValueIds = this.variants[index].facetValues.map(fv => fv.id);
+            return formFacetValueIds
+                .filter(x => !variantFacetValueIds.includes(x))
+                .map(id => this.facetValues.find(fv => fv.id === id))
+                .filter(notNullOrUndefined);
+        } else {
+            return [];
+        }
+    }
+
+    existingFacetValues(index: number) {
+        const variant = this.variants[index];
+        const formFacetValueIds = this.getFacetValueIds(index);
+        const intersection = [...formFacetValueIds].filter(x =>
+            variant.facetValues.map(fv => fv.id).includes(x),
+        );
+        return intersection
+            .map(id => variant.facetValues.find(fv => fv.id === id))
+            .filter(notNullOrUndefined);
+    }
+
+    removeFacetValue(index: number, facetValueId: string) {
+        const formGroup = this.formArray.at(index);
+        const newValue = (formGroup.value as VariantFormValue).facetValueIds.filter(
+            id => id !== facetValueId,
+        );
+        formGroup.patchValue({
+            facetValueIds: newValue,
+        });
+        formGroup.markAsDirty();
+    }
+
     isVariantSelected(variantId: string): boolean {
         return -1 < this.selectedVariantIds.indexOf(variantId);
     }
+
+    private getFacetValueIds(index: number): string[] {
+        const formValue: VariantFormValue = this.formArray.at(index).value;
+        return formValue.facetValueIds;
+    }
 }

+ 71 - 0
admin-ui/src/app/common/utilities/flatten-facet-values.spec.ts

@@ -0,0 +1,71 @@
+import { FacetWithValues, LanguageCode } from 'shared/generated-types';
+
+import { flattenFacetValues } from './flatten-facet-values';
+
+describe('flattenFacetValues()', () => {
+    it('works', () => {
+        const facetValue1 = {
+            id: '1',
+            languageCode: LanguageCode.en,
+            code: 'Balistreri,_Lesch_and_Crooks',
+            name: 'Balistreri, Lesch and Crooks',
+            translations: [],
+            facet: {} as any,
+        };
+        const facetValue2 = {
+            id: '2',
+            languageCode: LanguageCode.en,
+            code: 'Rodriguez_-_Von',
+            name: 'Rodriguez - Von',
+            translations: [],
+            facet: {} as any,
+        };
+        const facetValue3 = {
+            id: '3',
+            languageCode: LanguageCode.en,
+            code: 'Hahn_and_Sons',
+            name: 'Hahn and Sons',
+            translations: [],
+            facet: {} as any,
+        };
+        const facetValue4 = {
+            id: '4',
+            languageCode: LanguageCode.en,
+            code: 'Balistreri,_Lesch_and_Crooks',
+            name: 'Balistreri, Lesch and Crooks',
+            translations: [],
+            facet: {} as any,
+        };
+        const facetValue5 = {
+            id: '5',
+            languageCode: LanguageCode.en,
+            code: 'Rodriguez_-_Von',
+            name: 'Rodriguez - Von',
+            translations: [],
+            facet: {} as any,
+        };
+
+        const input: FacetWithValues.Fragment[] = [
+            {
+                id: '1',
+                languageCode: LanguageCode.en,
+                code: 'brand',
+                name: 'Brand',
+                translations: [],
+                values: [facetValue1, facetValue2, facetValue3],
+            },
+            {
+                id: '2',
+                languageCode: LanguageCode.en,
+                code: 'type',
+                name: 'Type',
+                translations: [],
+                values: [facetValue4, facetValue5],
+            },
+        ];
+
+        const result = flattenFacetValues(input);
+
+        expect(result).toEqual([facetValue1, facetValue2, facetValue3, facetValue4, facetValue5]);
+    });
+});

+ 8 - 0
admin-ui/src/app/common/utilities/flatten-facet-values.ts

@@ -0,0 +1,8 @@
+import { FacetValue, FacetWithValues } from 'shared/generated-types';
+
+export function flattenFacetValues(facetsWithValues: FacetWithValues.Fragment[]): FacetValue.Fragment[] {
+    return facetsWithValues.reduce(
+        (flattened, facet) => flattened.concat(facet.values),
+        [] as FacetValue.Fragment[],
+    );
+}

+ 4 - 0
admin-ui/src/app/data/definitions/facet-definitions.ts

@@ -11,6 +11,10 @@ export const FACET_VALUE_FRAGMENT = gql`
             languageCode
             name
         }
+        facet {
+            id
+            name
+        }
     }
 `;
 

+ 4 - 0
admin-ui/src/app/data/definitions/product-definitions.ts

@@ -40,6 +40,10 @@ export const PRODUCT_VARIANT_FRAGMENT = gql`
             id
             code
             name
+            facet {
+                id
+                name
+            }
         }
         translations {
             id

+ 3 - 1
admin-ui/src/app/data/providers/product-data.service.ts

@@ -105,7 +105,9 @@ export class ProductDataService {
 
     updateProductVariants(variants: UpdateProductVariantInput[]) {
         const input: UpdateProductVariants.Variables = {
-            input: variants.map(pick(['id', 'translations', 'sku', 'price', 'taxCategoryId'])),
+            input: variants.map(
+                pick(['id', 'translations', 'sku', 'price', 'taxCategoryId', 'facetValueIds']),
+            ),
         };
         return this.baseDataService.mutate<UpdateProductVariants.Mutation, UpdateProductVariants.Variables>(
             UPDATE_PRODUCT_VARIANTS,

+ 3 - 1
admin-ui/src/app/shared/components/chip/chip.component.html

@@ -1,6 +1,8 @@
 <div class="wrapper" [class.with-background]="colorFrom" [vdrBackgroundColorFrom]="colorFrom">
     <div class="chip-label"><ng-content></ng-content></div>
     <div class="chip-icon" *ngIf="icon">
-        <button (click)="iconClick.emit($event)"><clr-icon [attr.shape]="icon"></clr-icon></button>
+        <button (click)="iconClick.emit($event)">
+            <clr-icon [attr.shape]="icon" [class.is-inverse]="colorFrom"></clr-icon>
+        </button>
     </div>
 </div>

+ 3 - 1
admin-ui/src/app/shared/components/chip/chip.component.scss

@@ -21,8 +21,10 @@
 }
 
 .chip-icon {
-    border-left: 1px solid $color-grey-4;
+    border-left: 1px solid transparentize($color-grey-1, 0.5);
     padding: 0 3px;
+    line-height: 1em;
+    display: flex;
 
     button {
         cursor: pointer;

+ 4 - 0
admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.html

@@ -0,0 +1,4 @@
+<vdr-chip icon="times" [colorFrom]="facetValue.facet.name" (iconClick)="remove.emit()">
+    <span class="facet-name">{{ facetValue.facet.name }}</span>
+    {{ facetValue.name }}
+</vdr-chip>

+ 7 - 0
admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.scss

@@ -0,0 +1,7 @@
+@import "variables";
+
+.facet-name {
+    color: transparentize($color-grey-1, 0.5);
+    text-transform: uppercase;
+    font-size: 10px;
+}

+ 13 - 0
admin-ui/src/app/shared/components/facet-value-chip/facet-value-chip.component.ts

@@ -0,0 +1,13 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
+import { FacetValue } from 'shared/generated-types';
+
+@Component({
+    selector: 'vdr-facet-value-chip',
+    templateUrl: './facet-value-chip.component.html',
+    styleUrls: ['./facet-value-chip.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class FacetValueChipComponent {
+    @Input() facetValue: FacetValue.Fragment;
+    @Output() remove = new EventEmitter<void>();
+}

+ 2 - 0
admin-ui/src/app/shared/shared.module.ts

@@ -21,6 +21,7 @@ import { CustomFieldControlComponent } from './components/custom-field-control/c
 import { CustomerLabelComponent } from './components/customer-label/customer-label.component';
 import { DataTableColumnComponent } from './components/data-table/data-table-column.component';
 import { DataTableComponent } from './components/data-table/data-table.component';
+import { FacetValueChipComponent } from './components/facet-value-chip/facet-value-chip.component';
 import { FormFieldControlDirective } from './components/form-field/form-field-control.directive';
 import { FormFieldComponent } from './components/form-field/form-field.component';
 import { FormItemComponent } from './components/form-item/form-item.component';
@@ -66,6 +67,7 @@ const DECLARATIONS = [
     ItemsPerPageControlsComponent,
     PaginationControlsComponent,
     TableRowActionComponent,
+    FacetValueChipComponent,
     FileSizePipe,
     FormFieldComponent,
     FormFieldControlDirective,