Browse Source

feat(storefront): Use server pagination for facet detail page

Fixes #2576
Michael Bromley 2 years ago
parent
commit
6ca3265ec0
28 changed files with 235 additions and 206 deletions
  1. 27 23
      packages/admin-ui/i18n-coverage.json
  2. 12 0
      packages/admin-ui/src/lib/catalog/src/catalog.module.ts
  3. 24 0
      packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.html
  4. 0 0
      packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.scss
  5. 46 0
      packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.ts
  6. 5 5
      packages/admin-ui/src/lib/catalog/src/components/facet-detail/facet-detail.component.html
  7. 92 153
      packages/admin-ui/src/lib/catalog/src/components/facet-detail/facet-detail.component.ts
  8. 4 2
      packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts
  9. 3 1
      packages/admin-ui/src/lib/core/src/common/generated-types.ts
  10. 1 1
      packages/admin-ui/src/lib/core/src/data/definitions/facet-definitions.ts
  11. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/ar.json
  12. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  13. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  14. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  15. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  16. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/fa.json
  17. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  18. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/he.json
  19. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/hr.json
  20. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  21. 2 2
      packages/admin-ui/src/lib/static/i18n-messages/ne.json
  22. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  23. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  24. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  25. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  26. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  27. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  28. 1 1
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

+ 27 - 23
packages/admin-ui/i18n-coverage.json

@@ -1,46 +1,50 @@
 {
-  "generatedOn": "2023-10-17T19:32:07.745Z",
-  "lastCommit": "97bc099006adda7449a7b63e72191c2bb7e7b4ed",
-
+  "generatedOn": "2023-12-18T15:00:22.906Z",
+  "lastCommit": "4f42cf168eaee02eb73d6e70a6355265a88c4a05",
   "translationStatus": {
     "ar": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
       "percentage": 100
     },
     "cs": {
       "tokenCount": 761,
-      "translatedCount": 571,
+      "translatedCount": 570,
       "percentage": 75
     },
     "de": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
       "percentage": 100
     },
     "en": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
       "percentage": 100
     },
     "es": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
       "percentage": 100
     },
     "fa": {
       "tokenCount": 761,
-      "translatedCount": 736,
-      "percentage": 97
+      "translatedCount": 760,
+      "percentage": 100
     },
     "fr": {
       "tokenCount": 761,
-      "translatedCount": 758,
-      "percentage": 100
+      "translatedCount": 757,
+      "percentage": 99
     },
     "he": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
+      "percentage": 100
+    },
+    "hr": {
+      "tokenCount": 761,
+      "translatedCount": 759,
       "percentage": 100
     },
     "it": {
@@ -50,42 +54,42 @@
     },
     "ne": {
       "tokenCount": 761,
-      "translatedCount": 725,
-      "percentage": 95
+      "translatedCount": 749,
+      "percentage": 98
     },
     "pl": {
       "tokenCount": 761,
-      "translatedCount": 400,
-      "percentage": 53
+      "translatedCount": 399,
+      "percentage": 52
     },
     "pt_BR": {
       "tokenCount": 761,
-      "translatedCount": 760,
+      "translatedCount": 759,
       "percentage": 100
     },
     "pt_PT": {
       "tokenCount": 761,
-      "translatedCount": 609,
+      "translatedCount": 608,
       "percentage": 80
     },
     "ru": {
       "tokenCount": 761,
-      "translatedCount": 761,
+      "translatedCount": 760,
       "percentage": 100
     },
     "uk": {
       "tokenCount": 761,
-      "translatedCount": 596,
+      "translatedCount": 595,
       "percentage": 78
     },
     "zh_Hans": {
       "tokenCount": 761,
-      "translatedCount": 541,
+      "translatedCount": 540,
       "percentage": 71
     },
     "zh_Hant": {
       "tokenCount": 761,
-      "translatedCount": 387,
+      "translatedCount": 386,
       "percentage": 51
     }
   }

+ 12 - 0
packages/admin-ui/src/lib/catalog/src/catalog.module.ts

@@ -12,6 +12,7 @@ import {
     PageService,
     SharedModule,
 } from '@vendure/admin-ui/core';
+import { SortOrder } from '@vendure/common/lib/generated-types';
 
 import { createRoutes } from './catalog.routes';
 import { ApplyFacetDialogComponent } from './components/apply-facet-dialog/apply-facet-dialog.component';
@@ -34,6 +35,7 @@ import { CollectionListComponent } from './components/collection-list/collection
 import { CollectionTreeNodeComponent } from './components/collection-tree/collection-tree-node.component';
 import { CollectionTreeComponent } from './components/collection-tree/collection-tree.component';
 import { ConfirmVariantDeletionDialogComponent } from './components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';
+import { CreateFacetValueDialogComponent } from './components/create-facet-value-dialog/create-facet-value-dialog.component';
 import { CreateProductOptionGroupDialogComponent } from './components/create-product-option-group-dialog/create-product-option-group-dialog.component';
 import { CreateProductVariantDialogComponent } from './components/create-product-variant-dialog/create-product-variant-dialog.component';
 import { FacetDetailComponent } from './components/facet-detail/facet-detail.component';
@@ -101,6 +103,7 @@ const CATALOG_COMPONENTS = [
     CreateProductVariantDialogComponent,
     CreateProductOptionGroupDialogComponent,
     ProductVariantQuickJumpComponent,
+    CreateFacetValueDialogComponent,
 ];
 
 @NgModule({
@@ -207,6 +210,15 @@ export class CatalogModule {
             component: detailComponentWithResolver({
                 component: FacetDetailComponent,
                 query: GetFacetDetailDocument,
+                variables: {
+                    facetValueListOptions: {
+                        take: 10,
+                        skip: 0,
+                        sort: {
+                            createdAt: SortOrder.DESC,
+                        },
+                    },
+                },
                 entityKey: 'facet',
                 getBreadcrumbs: entity => [
                     {

+ 24 - 0
packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.html

@@ -0,0 +1,24 @@
+<ng-template vdrDialogTitle>
+    {{ 'catalog.create-facet-value' | translate }}
+</ng-template>
+<div class="form-grid" [formGroup]="form">
+    <vdr-form-field [label]="'common.name' | translate" for="name">
+        <input id="name" type="text" formControlName="name" (input)="updateCode()" />
+    </vdr-form-field>
+    <vdr-form-field
+        [label]="'common.code' | translate"
+        for="code"
+    >
+        <input
+            id="code"
+            type="text"
+            formControlName="code"
+        />
+    </vdr-form-field>
+</div>
+<ng-template vdrDialogButtons>
+    <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
+    <button type="submit" (click)="confirm()" class="btn btn-primary" [disabled]="form.invalid">
+        {{ 'common.confirm' | translate }}
+    </button>
+</ng-template>

+ 0 - 0
packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.scss


+ 46 - 0
packages/admin-ui/src/lib/catalog/src/components/create-facet-value-dialog/create-facet-value-dialog.component.ts

@@ -0,0 +1,46 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { FormBuilder, Validators } from '@angular/forms';
+import { CreateFacetValueInput, Dialog, LanguageCode } from '@vendure/admin-ui/core';
+
+import { normalizeString } from '@vendure/common/lib/normalize-string';
+
+@Component({
+    selector: 'vdr-create-facet-value-dialog',
+    templateUrl: './create-facet-value-dialog.component.html',
+    styleUrls: ['./create-facet-value-dialog.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CreateFacetValueDialogComponent implements Dialog<CreateFacetValueInput> {
+    resolveWith: (result?: CreateFacetValueInput) => void;
+    languageCode: LanguageCode;
+    form = this.formBuilder.group({
+        name: ['', Validators.required],
+        code: ['', Validators.required],
+    });
+    facetId: string;
+    constructor(private formBuilder: FormBuilder) {}
+
+    updateCode() {
+        const nameControl = this.form.get('name');
+        const codeControl = this.form.get('code');
+        if (nameControl && codeControl && codeControl.pristine) {
+            codeControl.setValue(normalizeString(`${nameControl.value}`, '-'));
+        }
+    }
+
+    confirm() {
+        const { name, code } = this.form.value;
+        if (!name || !code) {
+            return;
+        }
+        this.resolveWith({
+            facetId: this.facetId,
+            code,
+            translations: [{ languageCode: this.languageCode, name }],
+        });
+    }
+
+    cancel() {
+        this.resolveWith();
+    }
+}

+ 5 - 5
packages/admin-ui/src/lib/catalog/src/components/facet-detail/facet-detail.component.html

@@ -108,7 +108,7 @@
                         [placeholder]="'catalog.filter-by-name' | translate"
                     />
                 </ng-template>
-                <ng-container *ngIf="filteredValues$ | async as filteredValues">
+                <ng-container *ngIf="values$ | async as filteredValues">
                     <table class="facet-values-list table" formArrayName="values">
                         <thead>
                             <tr>
@@ -130,7 +130,7 @@
                                             : {
                                                   currentPage: currentPage,
                                                   itemsPerPage: itemsPerPage,
-                                                  totalItems: filteredValues.length
+                                                  totalItems: totalItems,
                                               };
                                     let i = index
                                 "
@@ -186,13 +186,13 @@
                     <div class="pagination-wrapper">
                         <vdr-items-per-page-controls
                             [itemsPerPage]="itemsPerPage"
-                            (itemsPerPageChange)="itemsPerPage = $event"
+                            (itemsPerPageChange)="setItemsPerPage($event)"
                         ></vdr-items-per-page-controls>
                         <vdr-pagination-controls
                             [currentPage]="currentPage"
                             [itemsPerPage]="itemsPerPage"
-                            [totalItems]="filteredValues.length"
-                            (pageChange)="currentPage = $event"
+                            [totalItems]="totalItems"
+                            (pageChange)="setCurrentPage($event)"
                         ></vdr-pagination-controls>
                     </div>
                 </ng-container>

+ 92 - 153
packages/admin-ui/src/lib/catalog/src/components/facet-detail/facet-detail.component.ts

@@ -11,15 +11,16 @@ import {
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     CreateFacetInput,
-    CreateFacetValueInput,
     createUpdatedTranslatable,
     DataService,
     DeletionResult,
-    FACET_WITH_VALUES_FRAGMENT,
-    FacetWithValuesFragment,
+    FACET_WITH_VALUE_LIST_FRAGMENT,
+    FacetWithValueListFragment,
     findTranslation,
     getCustomFieldsDefaults,
     GetFacetDetailDocument,
+    GetFacetDetailQuery,
+    GetFacetDetailQueryVariables,
     LanguageCode,
     ModalService,
     NotificationService,
@@ -28,22 +29,26 @@ import {
     UpdateFacetInput,
     UpdateFacetValueInput,
 } from '@vendure/admin-ui/core';
+import { SortOrder } from '@vendure/common/lib/generated-types';
 import { normalizeString } from '@vendure/common/lib/normalize-string';
 import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
 import { gql } from 'apollo-angular';
 import { BehaviorSubject, combineLatest, EMPTY, forkJoin, Observable } from 'rxjs';
-import { map, mergeMap, startWith, switchMap, take, tap } from 'rxjs/operators';
+import { debounceTime, map, mergeMap, switchMap, take, takeUntil } from 'rxjs/operators';
+import { CreateFacetValueDialogComponent } from '../create-facet-value-dialog/create-facet-value-dialog.component';
 
 export const FACET_DETAIL_QUERY = gql`
-    query GetFacetDetail($id: ID!) {
+    query GetFacetDetail($id: ID!, $facetValueListOptions: FacetValueListOptions) {
         facet(id: $id) {
-            ...FacetWithValues
+            ...FacetWithValueList
         }
     }
-    ${FACET_WITH_VALUES_FRAGMENT}
+    ${FACET_WITH_VALUE_LIST_FRAGMENT}
 `;
 
-type ValueItem = FacetWithValuesFragment['values'][number] | { id: string; name: string; code: string };
+type ValueItem =
+    | FacetWithValueListFragment['valueList']['items'][number]
+    | { id: string; name: string; code: string };
 
 @Component({
     selector: 'vdr-facet-detail',
@@ -75,9 +80,9 @@ export class FacetDetailComponent
     });
     currentPage = 1;
     itemsPerPage = 10;
+    totalItems = 0;
     filterControl = new FormControl('');
     values$ = new BehaviorSubject<ValueItem[]>([]);
-    filteredValues$ = new Observable<ValueItem[]>();
     readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateFacet];
 
     constructor(
@@ -92,24 +97,12 @@ export class FacetDetailComponent
 
     ngOnInit() {
         this.init();
-        this.filteredValues$ = combineLatest([
-            this.values$,
-            this.filterControl.valueChanges.pipe(startWith('')),
-        ]).pipe(
-            map(([values, filterTerm]) => {
-                const filterString = filterTerm?.toLowerCase().trim();
-                return filterString
-                    ? values.filter(
-                          v =>
-                              v.name.toLowerCase().includes(filterString) ||
-                              v.code.toLowerCase().includes(filterString),
-                      )
-                    : values;
-            }),
-            tap(() => {
+        this.filterControl.valueChanges
+            .pipe(debounceTime(200), takeUntil(this.destroy$))
+            .subscribe(filterTerm => {
                 this.currentPage = 1;
-            }),
-        );
+                this.fetchFacetValues(this.currentPage, this.itemsPerPage, filterTerm);
+            });
     }
 
     ngOnDestroy() {
@@ -139,33 +132,31 @@ export class FacetDetailComponent
     }
 
     addFacetValue() {
-        const valuesFormRecord = this.detailForm.get('values') as FormRecord;
-        if (valuesFormRecord) {
-            const id = this.createTempId();
-            const valueGroup = this.formBuilder.group({
-                id,
-                name: ['', Validators.required],
-                code: '',
-                customFields: this.formBuilder.group({}),
-            });
-            const newValue: any = { id, name: '', code: '' };
-            if (this.customValueFields.length) {
-                const customValueFieldsGroup = new UntypedFormGroup({});
-                newValue.customFields = {};
-
-                for (const fieldDef of this.customValueFields) {
-                    const key = fieldDef.name;
-                    customValueFieldsGroup.addControl(key, new UntypedFormControl());
+        this.modalService
+            .fromComponent(CreateFacetValueDialogComponent, {
+                locals: {
+                    languageCode: this.languageCode,
+                    facetId: this.id,
+                },
+            })
+            .pipe(
+                switchMap(result => {
+                    if (!result) {
+                        return EMPTY;
+                    } else {
+                        return this.dataService.facet.createFacetValues([result]);
+                    }
+                }),
+            )
+            .subscribe(result => {
+                if (result.createFacetValues) {
+                    this.notificationService.success(_('common.notify-create-success'), {
+                        entity: 'FacetValue',
+                    });
+                    this.currentPage = 1;
+                    this.fetchFacetValues(this.currentPage, this.itemsPerPage);
                 }
-
-                valueGroup.addControl('customFields', customValueFieldsGroup);
-            }
-            valuesFormRecord.addControl(id, valueGroup);
-            const values = this.values$.value;
-            const endOfPageIndex = this.currentPage * this.itemsPerPage - 1;
-            values.splice(endOfPageIndex, 0, newValue);
-            this.values$.next(values);
-        }
+            });
     }
 
     create() {
@@ -183,7 +174,6 @@ export class FacetDetailComponent
                 name: '',
                 code: '',
                 translations: [],
-                values: [],
             },
             facetForm,
             this.languageCode,
@@ -217,43 +207,21 @@ export class FacetDetailComponent
                     const updateOperations: Array<Observable<any>> = [];
 
                     if (facetForm && facetForm.dirty) {
-                        const newFacet = this.getUpdatedFacet(
+                        const updatedFacetInput = this.getUpdatedFacet(
                             facet,
                             facetForm,
                             languageCode,
                         ) as UpdateFacetInput;
-                        if (newFacet) {
-                            updateOperations.push(this.dataService.facet.updateFacet(newFacet));
+                        if (updatedFacetInput) {
+                            updateOperations.push(this.dataService.facet.updateFacet(updatedFacetInput));
                         }
                     }
                     if (valuesFormRecord && valuesFormRecord.dirty) {
-                        const createdValues = this.getCreatedFacetValues(
-                            facet,
-                            valuesFormRecord,
-                            languageCode,
-                        );
-                        if (createdValues.length) {
-                            updateOperations.push(
-                                this.dataService.facet.createFacetValues(createdValues).pipe(
-                                    switchMap(
-                                        () =>
-                                            this.dataService.query(GetFacetDetailDocument, {
-                                                id: this.id,
-                                            }).single$,
-                                    ),
-                                ),
-                            );
-                        }
-                        const updatedValues = this.getUpdatedFacetValues(
-                            facet,
-                            valuesFormRecord,
-                            languageCode,
-                        );
+                        const updatedValues = this.getUpdatedFacetValues(valuesFormRecord, languageCode);
                         if (updatedValues.length) {
                             updateOperations.push(this.dataService.facet.updateFacetValues(updatedValues));
                         }
                     }
-
                     return forkJoin(updateOperations);
                 }),
             )
@@ -272,16 +240,6 @@ export class FacetDetailComponent
     }
 
     deleteFacetValue(facetValueId: string) {
-        if (this.isTempId(facetValueId)) {
-            // deleting a newly-added (not persisted) FacetValue
-            const valuesFormRecord = this.detailForm.get('values') as FormRecord;
-            if (valuesFormRecord) {
-                valuesFormRecord.removeControl(facetValueId);
-            }
-            const values = this.values$.value;
-            this.values$.next(values.filter(v => v.id !== facetValueId));
-            return;
-        }
         this.showModalAndDelete(facetValueId)
             .pipe(
                 switchMap(response => {
@@ -303,13 +261,10 @@ export class FacetDetailComponent
             )
             .subscribe(
                 () => {
-                    const valuesFormRecord = this.detailForm.get('values') as FormRecord;
-                    if (valuesFormRecord) {
-                        valuesFormRecord.removeControl(facetValueId);
-                    }
                     this.notificationService.success(_('common.notify-delete-success'), {
                         entity: 'FacetValue',
                     });
+                    this.fetchFacetValues(this.currentPage, this.itemsPerPage, this.filterControl.value);
                 },
                 err => {
                     this.notificationService.error(_('common.notify-delete-error'), {
@@ -337,10 +292,42 @@ export class FacetDetailComponent
             );
     }
 
+    protected setCurrentPage(newPage: number) {
+        this.currentPage = newPage;
+        this.fetchFacetValues(this.currentPage, this.itemsPerPage, this.filterControl.value);
+    }
+
+    protected setItemsPerPage(itemsPerPage: number) {
+        this.itemsPerPage = itemsPerPage;
+        this.fetchFacetValues(this.currentPage, this.itemsPerPage, this.filterControl.value);
+    }
+
+    private fetchFacetValues(currentPage: number, itemsPerPage: number, filterTerm?: string | null) {
+        this.dataService
+            .query<GetFacetDetailQuery, GetFacetDetailQueryVariables>(FACET_DETAIL_QUERY, {
+                id: this.id,
+                facetValueListOptions: {
+                    take: itemsPerPage,
+                    skip: (currentPage - 1) * itemsPerPage,
+                    sort: {
+                        createdAt: SortOrder.DESC,
+                    },
+                    ...(filterTerm ? { filter: { name: { contains: filterTerm } } } : {}),
+                },
+            })
+            .single$.subscribe(({ facet }) => {
+                if (facet) {
+                    this.values$.next([...facet.valueList.items]);
+                    this.totalItems = facet.valueList.totalItems;
+                    this.setFacetValueFormValues(facet, this.languageCode);
+                }
+            });
+    }
+
     /**
      * Sets the values of the form on changes to the facet or current language.
      */
-    protected setFormValues(facet: FacetWithValuesFragment, languageCode: LanguageCode) {
+    protected setFormValues(facet: FacetWithValueListFragment, languageCode: LanguageCode) {
         const currentTranslation = findTranslation(facet, languageCode);
 
         this.detailForm.patchValue({
@@ -359,10 +346,14 @@ export class FacetDetailComponent
                 currentTranslation,
             );
         }
+        this.values$.next([...facet.valueList.items]);
+        this.totalItems = facet.valueList.totalItems;
+        this.setFacetValueFormValues(facet, languageCode);
+    }
 
+    private setFacetValueFormValues(facet: FacetWithValueListFragment, languageCode: LanguageCode) {
         const currentValuesFormGroup = this.detailForm.get('values') as FormRecord;
-        this.values$.next([...facet.values]);
-        facet.values.forEach(value => {
+        facet.valueList.items.forEach(value => {
             const valueTranslation = findTranslation(value, languageCode);
             const group = {
                 id: value.id,
@@ -370,11 +361,7 @@ export class FacetDetailComponent
                 name: valueTranslation ? valueTranslation.name : '',
             };
             let valueControl = currentValuesFormGroup.get(value.id) as FormGroup;
-            if (valueControl) {
-                valueControl.get('id')?.setValue(group.id);
-                valueControl.get('code')?.setValue(group.code);
-                valueControl.get('name')?.setValue(group.name);
-            } else {
+            if (!valueControl) {
                 valueControl = this.formBuilder.group(group);
                 currentValuesFormGroup.addControl(value.id, valueControl);
             }
@@ -411,7 +398,7 @@ export class FacetDetailComponent
      * can then be persisted to the API.
      */
     private getUpdatedFacet(
-        facet: FacetWithValuesFragment,
+        facet: Omit<FacetWithValueListFragment, 'valueList'>,
         facetFormGroup: (typeof this.detailForm)['controls']['facet'],
         languageCode: LanguageCode,
     ): CreateFacetInput | UpdateFacetInput {
@@ -429,63 +416,23 @@ export class FacetDetailComponent
         return input;
     }
 
-    /**
-     * Given an array of facet values and the values from the detailForm, this method creates a new array
-     * which can be persisted to the API via a createFacetValues mutation.
-     */
-    private getCreatedFacetValues(
-        facet: FacetWithValuesFragment,
-        valuesFormRecord: (typeof this.detailForm)['controls']['values'],
-        languageCode: LanguageCode,
-    ): CreateFacetValueInput[] {
-        return Object.values(valuesFormRecord.controls)
-            .filter(c => c.value.id && this.isTempId(c.value.id))
-            .map(c => c.value)
-            .map(value =>
-                createUpdatedTranslatable({
-                    translatable: { ...value, translations: [] as any },
-                    updatedFields: value ?? {},
-                    customFieldConfig: this.customValueFields,
-                    languageCode,
-                    defaultTranslation: {
-                        languageCode,
-                        name: '',
-                    },
-                }),
-            )
-            .map(input => ({
-                facetId: facet.id,
-                code: input.code ?? '',
-                ...input,
-                id: undefined,
-            }));
-    }
-
     /**
      * Given an array of facet values and the values from the detailForm, this method creates a new array
      * which can be persisted to the API via an updateFacetValues mutation.
      */
     private getUpdatedFacetValues(
-        facet: FacetWithValuesFragment,
         valuesFormGroup: FormGroup,
         languageCode: LanguageCode,
     ): UpdateFacetValueInput[] {
-        const dirtyValues = facet.values.filter(v => {
-            const formRow = valuesFormGroup.get(v.id);
-            return formRow && formRow.dirty && formRow.value.id;
-        });
         const dirtyValueValues = Object.values(valuesFormGroup.controls)
-            .filter(c => c.dirty && !this.isTempId(c.value.id))
+            .filter(c => c.dirty)
             .map(c => c.value);
 
-        if (dirtyValues.length !== dirtyValueValues.length) {
-            throw new Error(_(`error.facet-value-form-values-do-not-match`));
-        }
-        return dirtyValues
+        return dirtyValueValues
             .map((value, i) =>
                 createUpdatedTranslatable({
                     translatable: value,
-                    updatedFields: dirtyValueValues[i],
+                    updatedFields: value,
                     customFieldConfig: this.customValueFields,
                     languageCode,
                     defaultTranslation: {
@@ -496,12 +443,4 @@ export class FacetDetailComponent
             )
             .filter(notNullOrUndefined);
     }
-
-    private createTempId() {
-        return `temp-${Math.random().toString(36).substr(2, 9)}`;
-    }
-
-    private isTempId(id: string) {
-        return id.startsWith('temp-');
-    }
 }

+ 4 - 2
packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list.component.ts

@@ -3,7 +3,6 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     DataService,
     FACET_WITH_VALUE_LIST_FRAGMENT,
-    FACET_WITH_VALUES_FRAGMENT,
     GetFacetListDocument,
     GetFacetListQuery,
     ItemOf,
@@ -13,7 +12,7 @@ import {
 import { gql } from 'apollo-angular';
 
 export const FACET_LIST_QUERY = gql`
-    query GetFacetList($options: FacetListOptions) {
+    query GetFacetList($options: FacetListOptions, $facetValueListOptions: FacetValueListOptions) {
         facets(options: $options) {
             items {
                 ...FacetWithValueList
@@ -78,6 +77,9 @@ export class FacetListComponent
                     },
                     sort: this.sorts.createSortInput(),
                 },
+                facetValueListOptions: {
+                    take: 100,
+                },
             }),
             refreshListOnChanges: [this.filters.valueChanges, this.sorts.valueChanges],
         });

File diff suppressed because it is too large
+ 3 - 1
packages/admin-ui/src/lib/core/src/common/generated-types.ts


+ 1 - 1
packages/admin-ui/src/lib/core/src/data/definitions/facet-definitions.ts

@@ -57,7 +57,7 @@ export const FACET_WITH_VALUE_LIST_FRAGMENT = gql`
             languageCode
             name
         }
-        valueList(options: { take: 100 }) {
+        valueList(options: $facetValueListOptions) {
             totalItems
             items {
                 ...FacetValue

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "تم إجراء متغيرات المنتج التالية قديمة بسبب إضافة خيارات جديدة. سيتم حذفها أثناء إنشاء متغيرات المنتج الجديدة.",
     "confirm-deletion-of-unused-variants-title": "حذف متغيرات المنتجات القديمة؟",
     "create-draft-order": "إنشاء ترتيب مسودة",
+    "create-facet-value": "إنشاء قيمة جديدة للفئة",
     "create-new-collection": "إنشاء مجموعة جديدة",
     "create-new-facet": "إنشاء فئة جديد",
     "create-new-product": "منتج جديد",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "أنت غير مخول حاليًا للوصول إلى \" {path} \". إما أنك تفتقر إلى الأذونات , أو انتهت جلستك.",
     "could-not-connect-to-server": "لا يمكن الاتصال بخادم Vendure في {url}",
-    "facet-value-form-values-do-not-match": "عدد القيم في نموذج الفئة لا يتطابق مع العدد الفعلي للقيم",
     "health-check-failed": "فشل فحص صحة النظام",
     "no-default-shipping-zone-set": "هذه القناة لا تحتوي على منطقة شحن افتراضية. قد يتسبب هذا في حدوث أخطاء عند حساب رسوم الشحن.",
     "no-default-tax-zone-set": "لا تحتوي هذه القناة على منطقة ضريبية افتراضية , والتي ستسبب أخطاء عند حساب الأسعار. يرجى إنشاء أو تحديد منطقة."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
+    "create-facet-value": "Vytvořit novou hodnotu atributu",
     "create-new-collection": "Vytvořit kolekci",
     "create-new-facet": "Vytvořit nový atribut",
     "create-new-product": "Nový produkt",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Neautorizovaný přístup k \"{ path }\". Buďto nemáte oprávnění, nebo Vaše relace vypršela.",
     "could-not-connect-to-server": "Nelze se připojit k Vendure serveru na { url }",
-    "facet-value-form-values-do-not-match": "Počet hodnot ve formuláři atributu nesouhlasí k aktuálním počtem hodnot",
     "health-check-failed": "Kontrala stavu systému selhala",
     "no-default-shipping-zone-set": "Tento kanál nemá výchozí dodací zónu. To může způsobovat chyby při výpočtu poštovného.",
     "no-default-tax-zone-set": "Tento kanál nemá výchozí daňovou zónu, to může způsobovat chyby při výpočtu cen. Prosím vytvořte, nebo vyberte zónu."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Die folgenden Produktvarianten sind durch die Ergänzung neuer Optionen überflüssig geworden. Sie werden bei der Erstellung der neuen Produktvarianten gelöscht.",
     "confirm-deletion-of-unused-variants-title": "Überflüssige Produktvarianten löschen?",
     "create-draft-order": "Neue Bestellung",
+    "create-facet-value": "Neuen Facettenwert erstellen",
     "create-new-collection": "Neue Sammlung anlegen",
     "create-new-facet": "Neue Facette erstellen",
     "create-new-product": "Neues Produkt",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Sie sind derzeit nicht berechtigt, auf \"{ path }\" zuzugreifen. Entweder fehlen Ihnen die Berechtigungen, oder Ihre Sitzung ist abgelaufen.",
     "could-not-connect-to-server": "Es konnte keine Verbindung zum Vendure-Server auf { url } hergestellt werden.",
-    "facet-value-form-values-do-not-match": "Die Anzahl der Werte im Facetten-Formular stimmt nicht mit der tatsächlichen Anzahl der Werte überein",
     "health-check-failed": "Systemzustandsprüfung fehlgeschlagen",
     "no-default-shipping-zone-set": "Dieser Kanal verfügt nicht über eine Standard-Versandzone. Dies kann zu Fehlern bei der Berechnung der Auftragsversandkosten führen.",
     "no-default-tax-zone-set": "Dieser Kanal verfügt nicht über eine Standard-Steuerzone, was zu Fehlern bei der Preisberechnung führen kann. Bitte erstellen oder wählen Sie eine Zone."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "The following product variants have been made obsolete due to the addition of new options. They will be deleted during the creation of the new product variants.",
     "confirm-deletion-of-unused-variants-title": "Delete obsolete product variants?",
     "create-draft-order": "Create draft order",
+    "create-facet-value": "Create new facet value",
     "create-new-collection": "Create new collection",
     "create-new-facet": "Create new facet",
     "create-new-product": "New product",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "You are not currently authorized to access \"{ path }\". Either you lack permissions, or your session has expired.",
     "could-not-connect-to-server": "Could not connect to the Vendure server at { url }",
-    "facet-value-form-values-do-not-match": "The number of values in the facet form does not match the actual number of values",
     "health-check-failed": "System health check failed",
     "no-default-shipping-zone-set": "This channel has no default shipping zone. This may cause errors when calculating order shipping charges.",
     "no-default-tax-zone-set": "This channel has no default tax zone, which will cause errors when calculating prices. Please create or select a zone."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Las siguientes variantes de producto han quedado obsoletas debido a la incorporación de nuevas opciones. Se eliminarán durante la creación de las nuevas variantes de producto.",
     "confirm-deletion-of-unused-variants-title": "¿Eliminar variantes de producto obsoletas?",
     "create-draft-order": "Crear borrador de una orden",
+    "create-facet-value": "Crear nuevo valor de faceta",
     "create-new-collection": "Crear nueva colección",
     "create-new-facet": "Crear nueva faceta",
     "create-new-product": "Crear nuevo producto",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Actualmente no está autorizado para acceder a \"{ path }\". O bien carece de permisos, o su sesión ha expirado.",
     "could-not-connect-to-server": "No se ha podido conectar con el servidor de vendure en { url }",
-    "facet-value-form-values-do-not-match": "El número de valores en el formulario de la faceta no coincide con el número real de valores",
     "health-check-failed": "El sistema de control de integridad falló",
     "no-default-shipping-zone-set": "Este canal no tiene una zona de envío por defecto. Esto puede causar errores al calcular los gastos de envío del pedido.",
     "no-default-tax-zone-set": "Este canal no tiene una zona fiscal por defecto, lo que provocará errores al calcular los precios. Por favor, cree o seleccione una zona."

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/fa.json

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "انواع محصولات زیر به دلیل اضافه شدن قابلیت های جدید منسوخ شده اند. آنها در طول ایجاد انواع محصول جدید حذف خواهند شد.",
     "confirm-deletion-of-unused-variants-title": "آبا انواع محصولات منسوخ شده حذف شوند ؟",
     "create-draft-order": "ایجاد پیش نویس سفارش",
+    "create-facet-value": "ایجاد مقدار جدید برای ویژگی",
     "create-new-collection": "ایحاد مجموعه جدید",
     "create-new-facet": "ایحاد ویژگی جدید",
     "create-new-product": "ایجاد محصول جدید",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "شما در حال حاضر مجاز به دسترسی به \"{ path }\" نیستید. یا فاقد مجوز هستید یا جلسه شما منقضی شده است.",
     "could-not-connect-to-server": "اتصال به سرور امکان پذیر نیست",
-    "facet-value-form-values-do-not-match": "تعداد مقادیر در فرم ویژگی ها با تعداد واقعی مقادیر مطابقت ندارد",
     "health-check-failed": "بررسی سلامت سیستم ناموفق بود",
     "no-default-shipping-zone-set": "این کانال منطقه حمل و نقل پیش فرض ندارد. این ممکن است باعث ایجاد خطا در محاسبه هزینه ارسال سفارش شود.",
     "no-default-tax-zone-set": "این کانال فاقد منطقه مالیاتی پیش فرض است که باعث خطا در محاسبه قیمت ها می شود. لطفا یک منطقه ایجاد یا انتخاب کنید."
@@ -792,4 +792,4 @@
     "job-state-pending": "در انتظار",
     "job-state-running": "در حال اجرا"
   }
-}
+}

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Les variantes de produit suivantes sont devenues obsolètes en raison de l'ajout de nouvelles options. Elles seront supprimées lors de la création des nouvelles variantes de produit.",
     "confirm-deletion-of-unused-variants-title": "Supprimer les variantes de produits obsolètes ?",
     "create-draft-order": "Créer une commande en brouillon",
+    "create-facet-value": "Créer une nouvelle valeur du composant",
     "create-new-collection": "Créer nouvelle collection",
     "create-new-facet": "Créer nouveau composant",
     "create-new-product": "Nouveau produit",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Vous n'êtes pas autorisés à accéder à \"{ path }\". Vous n'avez pas la permission ou votre session a expiré.",
     "could-not-connect-to-server": "Connexion échoué au serveur Vendure à { url }",
-    "facet-value-form-values-do-not-match": "Le nombre de valeur dans le formulaire du composant ne correspond pas au nombre actuel de valeurs",
     "health-check-failed": "Vérification de santé du système a échoué",
     "no-default-shipping-zone-set": "Ce canal n'a pas de zone de livraison par défaut. Cela peut causer des erreur de calcul du cout de frais d'expédition.",
     "no-default-tax-zone-set": "Ce canal n'a pas de zone de taxe par défaut, ce qui peut causer des erreur lors du calcul du prix. Créez ou choisissez une zone."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "הווריאנטים של המוצר הבא הפכו ללא רלוונטיים בשל הוספת אפשרויות חדשות. הם ימחקו במהלך יצירת וריאנטים חדשים של המוצר.",
     "confirm-deletion-of-unused-variants-title": "למחוק וריאנטים מיותרים של מוצר?",
     "create-draft-order": "יצירת הזמנה טיוטה",
+    "create-facet-value": "צור ערך גבעול חדש",
     "create-new-collection": "צור אוסף חדש",
     "create-new-facet": "צור גבעול חדש",
     "create-new-product": "מוצר חדש",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "אין לך הרשאות לגשת כרגע ל \"{path}\". יתכן כי אין לך הרשאות מתאימות או שהפעלת ההפעלה שלך פגה.",
     "could-not-connect-to-server": "לא ניתן להתחבר לשרת Vendure בכתובת {url}",
-    "facet-value-form-values-do-not-match": "מספר הערכים בטופס התכונה לא תואם למספר הערכים הפיזיים",
     "health-check-failed": "בדיקת הבריאות של המערכת נכשלה",
     "no-default-shipping-zone-set": "לערוץ זה אין אזור משלוח ברירת מחדל. יתכן כי זה יגרום לשגיאות בחישוב דמי המשלוח של ההזמנה.",
     "no-default-tax-zone-set": "לערוץ זה אין אזור מס ברירת מחדל, וזה יגרום לשגיאות בחישוב המחירים. עליך ליצור אזור או לבחור אחד."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Sljedeće varijante proizvoda su postale zastarjele zbog dodavanja novih opcija. Bit će izbrisane tijekom stvaranja novih varijanti proizvoda.",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "Kreiraj privremenu narudžbu",
+    "create-facet-value": "Stvori novu vrijednost aspekta",
     "create-new-collection": "Kreiraj novu kolekciju",
     "create-new-facet": "Kreiraj novi aspekt",
     "create-new-product": "Novi proizvod",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Trenutno nemate ovlaštenje za pristup \"{ path }\". Ili vam nedostaju ovlasti ili je vaša sesija istekla.",
     "could-not-connect-to-server": "Nije moguće povezati se s Vendure serverom na { url }",
-    "facet-value-form-values-do-not-match": "Broj vrijednosti u obrascu za aspekte ne podudara se s stvarnim brojem vrijednosti",
     "health-check-failed": "Provjera zdravlja sustava nije uspjela",
     "no-default-shipping-zone-set": "Ovaj kanal nema zadaniu zonu dostave. To može uzrokovati pogreške pri izračunavanju troškova dostave narudžbe.",
     "no-default-tax-zone-set": "Ovaj kanal nema zadaniu poreznu zonu, što će uzrokovati pogreške pri izračunavanju cijena. Molimo kreirajte ili odaberite zonu."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Le seguenti varianti sono diventate obsolete a seguito dell'aggiunta di nuove opzioni. Queste verranno cancellate durante la creazione delle nuove varianti.",
     "confirm-deletion-of-unused-variants-title": "Cancellare le varianti obsolete?",
     "create-draft-order": "Crea bozza ordine",
+    "create-facet-value": "Crea nuovo valore attributo",
     "create-new-collection": "Crea nuova Collezione",
     "create-new-facet": "Crea nuovo attributo",
     "create-new-product": "Crea nuovo prodotto",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Non sei autorizzato ad accedere a \"{ path }\". Potresti non avere sufficienti permessi, oppure la tua sessione è scaduta.",
     "could-not-connect-to-server": "Non è stato possibile collegarsi al server Vendure a { url }",
-    "facet-value-form-values-do-not-match": "Il numero di valori nel modulo degli attributi non corrisponde al numero di valori",
     "health-check-failed": "La verifica del sistema ha dato esito negativo",
     "no-default-shipping-zone-set": "Questo canale non ha una zona di spedizione di default. Questo potrebbe causare errori nel calcolo dei prezzi di spedizione.",
     "no-default-tax-zone-set": "Questo canale non ha una zona di tassazione di default. Questo sarà causa di errori nel calcolo dei prezzi. Per favore seleziona una zona."
@@ -792,4 +792,4 @@
     "job-state-pending": "In attesa",
     "job-state-running": "In esecuzione"
   }
-}
+}

+ 2 - 2
packages/admin-ui/src/lib/static/i18n-messages/ne.json

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "नयाँ विकल्पहरू थप्दा पुरानो समान विविधताहरूमा प्रयुक्त भएको कारण पुरानो समान विविधताहरू मेटाइनेछन्।",
     "confirm-deletion-of-unused-variants-title": "अपयोगित समान विविधताहरू मेटाउनुहोस्?",
     "create-draft-order": "मस्यौदा ओर्दर सिर्जना गर्नुहोस्",
+    "create-facet-value": "नयाँ गुणस्तर मान बनाउनुहोस्",
     "create-new-collection": "",
     "create-new-facet": "नयाँ मूल्य सिर्जना गर्नुहोस्",
     "create-new-product": "नयाँ समान",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "तपाईंलाई हालको गरेदिनुपर्दै \"{ path }\" मा पहुँच गर्न पाइएन। तपाईंको पासवर्ड, वा तपाईंको सत्र समाप्त भएको छ भने हेरचाह गर्नुहोस्।",
     "could-not-connect-to-server": "Vendure सर्भरसँग कनेक्ट गर्न सक्दैन at { url }",
-    "facet-value-form-values-do-not-match": "फ्यासेट फारमको मूल्यहरूको मिलन गर्दैन",
     "health-check-failed": "सिस्टम स्वास्थ्य परीक्षण असफल भयो",
     "no-default-shipping-zone-set": "यस प्रकारको कुनै पनि परियोजना पूरा गरिएको छैन। यसले अर्डर लेखन गर्दा फ्राइट काटो मूल्यहरू परिस्थिति पार्ट गर्दा त्रुटिहरू पैदा गर्दछ।",
     "no-default-tax-zone-set": "यस प्रकारको कुनै पनि परियोजना मा आपरेटिंग स्वतः लागू हुने क्षेत्र छैन, जसले मूल्यहरू गन गर्दा त्रुटिहरू पैदा गर्दछ। कृपया एक ठाउँ बनाउनुहोस् वा चयन गर्नुहोस्।"
@@ -792,4 +792,4 @@
     "job-state-pending": "बाँकी",
     "job-state-running": "चलिरहेको"
   }
-}
+}

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
+    "create-facet-value": "Utwórz nową wartość fasety",
     "create-new-collection": "Utwórz nową kolekcje",
     "create-new-facet": "Utwórz faset",
     "create-new-product": "Nowy produkt",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "Brak autoryzacji dla \"{ path }\". Brak uprawnień lub wygasła sesja.",
     "could-not-connect-to-server": "Nie można połączyć z serverem Vendure na { url }",
-    "facet-value-form-values-do-not-match": "Ilość wartości fasetów nie zgadza się z realną liczbą wartości.",
     "health-check-failed": "",
     "no-default-shipping-zone-set": "",
     "no-default-tax-zone-set": ""

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "As seguintes variantes de produtos foram tornadas obsoletas devido à adição de novas opções. Eles serão excluídos durante a criação das novas variantes do produto",
     "confirm-deletion-of-unused-variants-title": "Excluir variantes de produtos obsoletos?",
     "create-draft-order": "Criar rascunho de pedido",
+    "create-facet-value": "Criar novo valor para etiqueta",
     "create-new-collection": "Criar nova categoria",
     "create-new-facet": "Criar nova etiqueta",
     "create-new-product": "Novo produto",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "No momento, você não está autorizado a acessar \"{ path }\". Você não tem permissão ou sua sessão expirou.",
     "could-not-connect-to-server": "Não foi possível ao servidor Mercado NetBrit no link { url }",
-    "facet-value-form-values-do-not-match": "O número de valores no formulário de etiqueta não corresponde ao número real de valores",
     "health-check-failed": "Falha na verificação de integridade do sistema",
     "no-default-shipping-zone-set": "Este canal não possui zona de entrega padrão. Isso pode causar erros ao calcular as despesas de envio do pedido.",
     "no-default-tax-zone-set": "Este canal não possui zona de imposto padrão, o que causará erros no cálculo de preços. Por favor, crie ou selecione uma zona."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "As variantes listadas abaixo estão obsoletas e serão eliminadas devido à adição de novas opções.",
     "confirm-deletion-of-unused-variants-title": "Eliminar as variantes obsoletas?",
     "create-draft-order": "",
+    "create-facet-value": "",
     "create-new-collection": "Criar nova categoria",
     "create-new-facet": "Criar nova etiqueta",
     "create-new-product": "Novo produto",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "No momento, você não está autorizado a aceder \"{ path }\". Você não tem permissão ou a sua sessão expirou.",
     "could-not-connect-to-server": "Não foi possível conectar-se ao servidor Vendure",
-    "facet-value-form-values-do-not-match": "O número de valores no formulário de etiqueta não corresponde ao número real de valores",
     "health-check-failed": "Falha na verificação de integridade do sistema",
     "no-default-shipping-zone-set": "O canal não possui regiões de entrega padrão. Poderá ocorrer erros ao calcular as despesas de envio da encomenda.",
     "no-default-tax-zone-set": "O canal não possui regiões de imposto padrão, o que causará erros no cálculo dos preços. Por favor, crie ou seleccione uma região."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Следующие варианты товаров устарели из за добавления новых опций. Они будут удалены во время создания новых вариантов товара.",
     "confirm-deletion-of-unused-variants-title": "Удалить устаревшие варианты товара?",
     "create-draft-order": "Создать черновик заказа",
+    "create-facet-value": "Создать новое значение тега",
     "create-new-collection": "Создать новую коллекцию",
     "create-new-facet": "Создать новый тег",
     "create-new-product": "Создать новый товар",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "В настоящее время у вас нет прав доступа \"{ path }\". Либо у вас нет разрешений на просмотр, либо срок вашего сеанса истек.",
     "could-not-connect-to-server": "Не удалось подключиться к серверу Vendure на { url }",
-    "facet-value-form-values-do-not-match": "Количество значений в форме тегов не соответствует фактическому количеству значений.",
     "health-check-failed": "Ошибка проверки работоспособности системы",
     "no-default-shipping-zone-set": "Этот канал не имеет зоны доставки по умолчанию. Это может вызвать ошибки при расчете стоимости доставки заказа.",
     "no-default-tax-zone-set": "Этот канал не имеет налоговой зоны по умолчанию, что приведет к ошибкам при расчете цен. Пожалуйста, создайте или выберите зону."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "Наступні варіанти товару застаріли через додавання нових опцій. Вони будуть видалені під час створення нових варіантів товару.",
     "confirm-deletion-of-unused-variants-title": "Видалити застарілі варіанти товару?",
     "create-draft-order": "",
+    "create-facet-value": "Створити нове значення тегу",
     "create-new-collection": "Створити нову колекцію",
     "create-new-facet": "Створити новий тег",
     "create-new-product": "Створити новий товар",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "В даний час у вас немає прав доступу \"{ path }\". Або у вас немає дозволів на перегляд, або термін вашого сеансу минув.",
     "could-not-connect-to-server": "Не вдалося підключитися до сервера Vendure на { url }",
-    "facet-value-form-values-do-not-match": "Кількість значень у формі тегів не відповідає фактичній кількості значень.",
     "health-check-failed": "Помилка перевірки працездатності системи",
     "no-default-shipping-zone-set": "Цей канал не має зони доставки за замовчуванням. Це може викликати помилки при розрахунку вартості доставки замовлення.",
     "no-default-tax-zone-set": "Цей канал не має податкової зони за замовчуванням, що призведе до помилок при розрахунку цін. Будь ласка, створіть або виберіть зону."

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
+    "create-facet-value": "创建新特征值",
     "create-new-collection": "添加系列",
     "create-new-facet": "添加特征",
     "create-new-product": "添加商品",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "无权限访问路径 \"{ path }\"。无权限或会话已过期,请重新登陆",
     "could-not-connect-to-server": "无法链接服务器 { url }",
-    "facet-value-form-values-do-not-match": "表单中商品特征值数量与实际不符",
     "health-check-failed": "系统健康状态检查失败",
     "no-default-shipping-zone-set": "当前销售渠道没有默认配送区域设置,这会导致计算邮费失败。",
     "no-default-tax-zone-set": "当前销售渠道没有没人税表区域设置,这会导致计算价格失败。请创建或选择税区。"

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

@@ -89,6 +89,7 @@
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
+    "create-facet-value": "建立新特徵值",
     "create-new-collection": "新增系列",
     "create-new-facet": "新增特徵",
     "create-new-product": "新增商品",
@@ -478,7 +479,6 @@
   "error": {
     "403-forbidden": "無權限存取路徑 \"{ path }\"。無權限或會話已經逾期,請重新登入",
     "could-not-connect-to-server": "無法連接伺服器 { url }",
-    "facet-value-form-values-do-not-match": "表單中商品特徵值數量與實際不符",
     "health-check-failed": "",
     "no-default-shipping-zone-set": "",
     "no-default-tax-zone-set": ""

Some files were not shown because too many files changed in this diff