Browse Source

feat(admin-ui): Allow editing of FacetValue customFields

Michael Bromley 7 years ago
parent
commit
07f8f598fd

+ 11 - 0
admin-ui/src/app/catalog/components/facet-detail/facet-detail.component.html

@@ -58,6 +58,9 @@
             <tr>
                 <th>{{ 'catalog.name' | translate }}</th>
                 <th>{{ 'catalog.code' | translate }}</th>
+                <ng-container *ngFor="let customField of customValueFields">
+                    <th>{{ customField.name }}</th>
+                </ng-container>
             </tr>
             </thead>
             <tbody>
@@ -70,6 +73,14 @@
                 <td>
                     <input type="text" formControlName="code" readonly>
                 </td>
+                <ng-container *ngFor="let customField of customValueFields">
+                    <td>
+                        <vdr-custom-field-control *ngIf="customValueFieldIsSet(i, customField.name)"
+                                                  [showLabel]="false"
+                                                  [customFieldsFormGroup]="facetForm.get(['values', i, 'customFields'])"
+                                                  [customField]="customField"></vdr-custom-field-control>
+                    </td>
+                </ng-container>
             </tr>
             </tbody>
         </table>

+ 42 - 5
admin-ui/src/app/catalog/components/facet-detail/facet-detail.component.ts

@@ -1,5 +1,5 @@
-import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
-import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { combineLatest, forkJoin, Observable, Subject } from 'rxjs';
 import { map, mergeMap, switchMap, take, takeUntil } from 'rxjs/operators';
@@ -39,6 +39,7 @@ export class FacetDetailComponent implements OnInit, OnDestroy {
     private destroy$ = new Subject<void>();
 
     constructor(
+        private changeDetector: ChangeDetectorRef,
         private dataService: DataService,
         private router: Router,
         private route: ActivatedRoute,
@@ -102,6 +103,10 @@ export class FacetDetailComponent implements OnInit, OnDestroy {
         return !!this.facetForm.get(['facet', 'customFields', name]);
     }
 
+    customValueFieldIsSet(index: number, name: string): boolean {
+        return !!this.facetForm.get(['values', index, 'customFields', name]);
+    }
+
     getValuesFormArray(): FormArray {
         return this.facetForm.get('values') as FormArray;
     }
@@ -130,6 +135,7 @@ export class FacetDetailComponent implements OnInit, OnDestroy {
                 data => {
                     this.notificationService.success(_('catalog.notify-create-facet-success'));
                     this.facetForm.markAsPristine();
+                    this.changeDetector.markForCheck();
                     this.router.navigate(['../', data.createFacet.id], { relativeTo: this.route });
                 },
                 err => {
@@ -180,6 +186,7 @@ export class FacetDetailComponent implements OnInit, OnDestroy {
             .subscribe(
                 () => {
                     this.facetForm.markAsPristine();
+                    this.changeDetector.markForCheck();
                     this.notificationService.success(_('catalog.notify-update-facet-success'));
                 },
                 err => {
@@ -221,18 +228,48 @@ export class FacetDetailComponent implements OnInit, OnDestroy {
 
             const valuesFormArray = this.facetForm.get('values') as FormArray;
             facet.values.forEach((value, i) => {
-                const variantTranslation = value.translations.find(t => t.languageCode === languageCode);
+                const valueTranslation = value.translations.find(t => t.languageCode === languageCode);
                 const group = {
                     id: value.id,
                     code: value.code,
-                    name: variantTranslation ? variantTranslation.name : '',
+                    name: valueTranslation ? valueTranslation.name : '',
                 };
                 const existing = valuesFormArray.at(i);
                 if (existing) {
-                    existing.setValue(group);
+                    existing.patchValue(group);
                 } else {
                     valuesFormArray.insert(i, this.formBuilder.group(group));
                 }
+                if (this.customValueFields.length) {
+                    let customValueFieldsGroup = this.facetForm.get([
+                        'values',
+                        i,
+                        'customFields',
+                    ]) as FormGroup;
+                    if (!customValueFieldsGroup) {
+                        customValueFieldsGroup = new FormGroup({});
+                        (this.facetForm.get(['values', i]) as FormGroup).addControl(
+                            'customFields',
+                            customValueFieldsGroup,
+                        );
+                    }
+
+                    if (customValueFieldsGroup) {
+                        for (const fieldDef of this.customValueFields) {
+                            const key = fieldDef.name;
+                            const fieldValue =
+                                fieldDef.type === 'localeString'
+                                    ? (valueTranslation as any).customFields[key]
+                                    : (value as any).customFields[key];
+                            const control = customValueFieldsGroup.get(key);
+                            if (control) {
+                                control.setValue(fieldValue);
+                            } else {
+                                customValueFieldsGroup.addControl(key, new FormControl(fieldValue));
+                            }
+                        }
+                    }
+                }
             });
         }
     }

+ 2 - 2
admin-ui/src/app/data/providers/facet-data.service.ts

@@ -77,7 +77,7 @@ export class FacetDataService {
 
     createFacetValues(facetValues: CreateFacetValueInput[]): Observable<CreateFacetValues> {
         const input: CreateFacetValuesVariables = {
-            input: facetValues.map(pick(['facetId', 'code', 'translations'])),
+            input: facetValues.map(pick(['facetId', 'code', 'translations', 'customFields'])),
         };
         return this.baseDataService.mutate<CreateFacetValues, CreateFacetValuesVariables>(
             addCustomFields(CREATE_FACET_VALUES),
@@ -87,7 +87,7 @@ export class FacetDataService {
 
     updateFacetValues(facetValues: UpdateFacetValueInput[]): Observable<UpdateFacetValues> {
         const input: UpdateFacetValuesVariables = {
-            input: facetValues.map(pick(['id', 'code', 'translations'])),
+            input: facetValues.map(pick(['id', 'code', 'translations', 'customFields'])),
         };
         return this.baseDataService.mutate<UpdateFacetValues, UpdateFacetValuesVariables>(
             addCustomFields(UPDATE_FACET_VALUES),

+ 141 - 138
admin-ui/src/app/data/types/gql-generated-types.ts

@@ -906,6 +906,29 @@ export interface GetProductOptionGroupsVariables {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
+// ====================================================
+// GraphQL fragment: FacetValue
+// ====================================================
+
+export interface FacetValue_translations {
+  __typename: "FacetValueTranslation";
+  id: string;
+  languageCode: LanguageCode;
+  name: string;
+}
+
+export interface FacetValue {
+  __typename: "FacetValue";
+  id: string;
+  languageCode: LanguageCode | null;
+  code: string;
+  name: string;
+  translations: FacetValue_translations[];
+}
+
+/* tslint:disable */
+// This file was automatically generated and should not be edited.
+
 // ====================================================
 // GraphQL fragment: FacetWithValues
 // ====================================================
@@ -946,29 +969,6 @@ export interface FacetWithValues {
 /* tslint:disable */
 // This file was automatically generated and should not be edited.
 
-// ====================================================
-// GraphQL fragment: FacetValue
-// ====================================================
-
-export interface FacetValue_translations {
-  __typename: "FacetValueTranslation";
-  id: string;
-  languageCode: LanguageCode;
-  name: string;
-}
-
-export interface FacetValue {
-  __typename: "FacetValue";
-  id: string;
-  languageCode: LanguageCode | null;
-  code: string;
-  name: string;
-  translations: FacetValue_translations[];
-}
-
-/* tslint:disable */
-// This file was automatically generated and should not be edited.
-
 // ====================================================
 // GraphQL fragment: ProductVariant
 // ====================================================
@@ -1301,75 +1301,29 @@ export enum SortOrder {
   DESC = "DESC",
 }
 
-export interface CreateFacetInput {
-  code: string;
-  translations: FacetTranslationInput[];
-  values?: CreateFacetValueInput[] | null;
-  customFields?: CreateFacetCustomFieldsInput | null;
-}
-
-export interface FacetTranslationInput {
-  id?: string | null;
-  languageCode: LanguageCode;
-  name: string;
-  customFields?: any | null;
-}
-
-export interface CreateFacetValueInput {
-  facetId: string;
-  code: string;
-  translations: FacetValueTranslationInput[];
-}
-
-export interface FacetValueTranslationInput {
-  id?: string | null;
-  languageCode: LanguageCode;
-  name: string;
+export interface BooleanOperators {
+  eq?: boolean | null;
 }
 
 export interface CreateFacetCustomFieldsInput {
   searchable?: boolean | null;
 }
 
-export interface UpdateFacetInput {
-  id: string;
+export interface CreateFacetInput {
   code: string;
   translations: FacetTranslationInput[];
-  customFields?: UpdateFacetCustomFieldsInput | null;
-}
-
-export interface UpdateFacetCustomFieldsInput {
-  searchable?: boolean | null;
+  values?: CreateFacetValueInput[] | null;
+  customFields?: CreateFacetCustomFieldsInput | null;
 }
 
-export interface UpdateFacetValueInput {
-  id: string;
+export interface CreateFacetValueInput {
+  facetId: string;
   code: string;
   translations: FacetValueTranslationInput[];
+  customFields?: any | null;
 }
 
-export interface UpdateProductInput {
-  id: string;
-  image?: string | null;
-  translations: (ProductTranslationInput | null)[];
-  optionGroupCodes?: (string | null)[] | null;
-  customFields?: UpdateProductCustomFieldsInput | null;
-}
-
-export interface ProductTranslationInput {
-  id?: string | null;
-  languageCode: LanguageCode;
-  name: string;
-  slug?: string | null;
-  description?: string | null;
-  customFields?: ProductTranslationCustomFieldsInput | null;
-}
-
-export interface ProductTranslationCustomFieldsInput {
-  nickname?: string | null;
-}
-
-export interface UpdateProductCustomFieldsInput {
+export interface CreateProductCustomFieldsInput {
   infoUrl?: string | null;
   downloadable?: boolean | null;
 }
@@ -1381,27 +1335,6 @@ export interface CreateProductInput {
   customFields?: CreateProductCustomFieldsInput | null;
 }
 
-export interface CreateProductCustomFieldsInput {
-  infoUrl?: string | null;
-  downloadable?: boolean | null;
-}
-
-export interface UpdateProductVariantInput {
-  id: string;
-  translations: ProductVariantTranslationInput[];
-  sku: string;
-  image?: string | null;
-  price: number;
-  customFields?: any | null;
-}
-
-export interface ProductVariantTranslationInput {
-  id?: string | null;
-  languageCode: LanguageCode;
-  name: string;
-  customFields?: any | null;
-}
-
 export interface CreateProductOptionGroupInput {
   code: string;
   translations: ProductOptionGroupTranslationInput[];
@@ -1409,19 +1342,32 @@ export interface CreateProductOptionGroupInput {
   customFields?: any | null;
 }
 
-export interface ProductOptionGroupTranslationInput {
-  id?: string | null;
-  languageCode: LanguageCode;
-  name: string;
-  customFields?: any | null;
-}
-
 export interface CreateProductOptionInput {
   code: string;
   translations: ProductOptionGroupTranslationInput[];
   customFields?: any | null;
 }
 
+export interface DateOperators {
+  eq?: any | null;
+  before?: any | null;
+  after?: any | null;
+  between?: DateRange | null;
+}
+
+export interface DateRange {
+  start: any;
+  end: any;
+}
+
+export interface FacetFilterParameter {
+  name?: StringOperators | null;
+  code?: StringOperators | null;
+  createdAt?: DateOperators | null;
+  updatedAt?: DateOperators | null;
+  searchable?: BooleanOperators | null;
+}
+
 export interface FacetListOptions {
   take?: number | null;
   skip?: number | null;
@@ -1438,33 +1384,29 @@ export interface FacetSortParameter {
   searchable?: SortOrder | null;
 }
 
-export interface FacetFilterParameter {
-  name?: StringOperators | null;
-  code?: StringOperators | null;
-  createdAt?: DateOperators | null;
-  updatedAt?: DateOperators | null;
-  searchable?: BooleanOperators | null;
-}
-
-export interface StringOperators {
-  eq?: string | null;
-  contains?: string | null;
-}
-
-export interface DateOperators {
-  eq?: any | null;
-  before?: any | null;
-  after?: any | null;
-  between?: DateRange | null;
+export interface FacetTranslationInput {
+  id?: string | null;
+  languageCode: LanguageCode;
+  name: string;
+  customFields?: any | null;
 }
 
-export interface DateRange {
-  start: any;
-  end: any;
+export interface FacetValueTranslationInput {
+  id?: string | null;
+  languageCode: LanguageCode;
+  name: string;
+  customFields?: any | null;
 }
 
-export interface BooleanOperators {
-  eq?: boolean | null;
+export interface ProductFilterParameter {
+  name?: StringOperators | null;
+  slug?: StringOperators | null;
+  description?: StringOperators | null;
+  createdAt?: DateOperators | null;
+  updatedAt?: DateOperators | null;
+  infoUrl?: StringOperators | null;
+  downloadable?: BooleanOperators | null;
+  nickname?: StringOperators | null;
 }
 
 export interface ProductListOptions {
@@ -1474,6 +1416,13 @@ export interface ProductListOptions {
   filter?: ProductFilterParameter | null;
 }
 
+export interface ProductOptionGroupTranslationInput {
+  id?: string | null;
+  languageCode: LanguageCode;
+  name: string;
+  customFields?: any | null;
+}
+
 export interface ProductSortParameter {
   id?: SortOrder | null;
   createdAt?: SortOrder | null;
@@ -1487,15 +1436,69 @@ export interface ProductSortParameter {
   nickname?: SortOrder | null;
 }
 
-export interface ProductFilterParameter {
-  name?: StringOperators | null;
-  slug?: StringOperators | null;
-  description?: StringOperators | null;
-  createdAt?: DateOperators | null;
-  updatedAt?: DateOperators | null;
-  infoUrl?: StringOperators | null;
-  downloadable?: BooleanOperators | null;
-  nickname?: StringOperators | null;
+export interface ProductTranslationCustomFieldsInput {
+  nickname?: string | null;
+}
+
+export interface ProductTranslationInput {
+  id?: string | null;
+  languageCode: LanguageCode;
+  name: string;
+  slug?: string | null;
+  description?: string | null;
+  customFields?: ProductTranslationCustomFieldsInput | null;
+}
+
+export interface ProductVariantTranslationInput {
+  id?: string | null;
+  languageCode: LanguageCode;
+  name: string;
+  customFields?: any | null;
+}
+
+export interface StringOperators {
+  eq?: string | null;
+  contains?: string | null;
+}
+
+export interface UpdateFacetCustomFieldsInput {
+  searchable?: boolean | null;
+}
+
+export interface UpdateFacetInput {
+  id: string;
+  code: string;
+  translations: FacetTranslationInput[];
+  customFields?: UpdateFacetCustomFieldsInput | null;
+}
+
+export interface UpdateFacetValueInput {
+  id: string;
+  code: string;
+  translations: FacetValueTranslationInput[];
+  customFields?: any | null;
+}
+
+export interface UpdateProductCustomFieldsInput {
+  infoUrl?: string | null;
+  downloadable?: boolean | null;
+}
+
+export interface UpdateProductInput {
+  id: string;
+  image?: string | null;
+  translations: (ProductTranslationInput | null)[];
+  optionGroupCodes?: (string | null)[] | null;
+  customFields?: UpdateProductCustomFieldsInput | null;
+}
+
+export interface UpdateProductVariantInput {
+  id: string;
+  translations: ProductVariantTranslationInput[];
+  sku: string;
+  image?: string | null;
+  price: number;
+  customFields?: any | null;
 }
 
 //==============================================================

+ 1 - 1
admin-ui/src/app/shared/components/custom-field-control/custom-field-control.component.html

@@ -1,4 +1,4 @@
-<vdr-form-field [label]="customField.name"
+<vdr-form-field [label]="label"
                 [for]="customField.name">
     <input *ngIf="customField.type === 'string' || customField.type === 'localeString'"
            type="text"

+ 9 - 1
admin-ui/src/app/shared/components/custom-field-control/custom-field-control.component.ts

@@ -12,7 +12,15 @@ import { CustomFieldConfig } from '../../../../../../shared/shared-types';
     templateUrl: './custom-field-control.component.html',
     styleUrls: ['./custom-field-control.component.scss'],
 })
-export class CustomFieldControlComponent {
+export class CustomFieldControlComponent implements OnInit {
     @Input('customFieldsFormGroup') formGroup: FormGroup;
     @Input() customField: CustomFieldConfig;
+    @Input() showLabel = true;
+    label: string;
+
+    ngOnInit() {
+        if (this.showLabel) {
+            this.label = this.customField.name;
+        }
+    }
 }

+ 4 - 2
admin-ui/src/app/shared/components/form-field/form-field.component.html

@@ -1,5 +1,7 @@
-<div class="form-group">
-    <label [for]="for">{{ label }}
+<div class="form-group"
+    [class.no-label]="!label">
+    <label *ngIf="label"
+           [for]="for">{{ label }}
         <clr-tooltip *ngIf="tooltip">
             <clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
             <clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>

+ 12 - 0
admin-ui/src/app/shared/components/form-field/form-field.component.scss

@@ -13,6 +13,18 @@
     .form-group .tooltip-validation {
         height: initial;
     }
+    .form-group.no-label {
+        margin: -6px 0 0 0;
+        padding: 0;
+        justify-content: center;
+        > label {
+            position: relative;
+            justify-content: center;
+        }
+        .input-row {
+            justify-content: center;
+        }
+    }
     .input-row {
         display: flex;
         ::ng-deep input {