Browse Source

Merge branch 'master' into next

Michael Bromley 5 years ago
parent
commit
ff0d1535bb
26 changed files with 277 additions and 79 deletions
  1. 18 0
      CHANGELOG.md
  2. 1 1
      lerna.json
  3. 2 2
      packages/admin-ui-plugin/package.json
  4. 1 1
      packages/admin-ui/package.json
  5. 3 0
      packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts
  6. 1 1
      packages/admin-ui/src/lib/core/src/common/version.ts
  7. 4 45
      packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.html
  8. 31 4
      packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.ts
  9. 84 0
      packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.html
  10. 5 0
      packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.scss
  11. 30 0
      packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.ts
  12. 1 0
      packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.html
  13. 20 3
      packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.ts
  14. 2 0
      packages/admin-ui/src/lib/customer/src/customer.module.ts
  15. 1 0
      packages/admin-ui/src/lib/customer/src/public_api.ts
  16. 2 2
      packages/asset-server-plugin/package.json
  17. 28 0
      packages/core/e2e/asset.e2e-spec.ts
  18. 20 0
      packages/core/e2e/graphql/generated-e2e-admin-types.ts
  19. 1 1
      packages/core/package.json
  20. 3 0
      packages/core/src/api/common/graphql-value-transformer.ts
  21. 2 2
      packages/create/package.json
  22. 8 8
      packages/dev-server/package.json
  23. 2 2
      packages/elasticsearch-plugin/package.json
  24. 2 2
      packages/email-plugin/package.json
  25. 2 2
      packages/testing/package.json
  26. 3 3
      packages/ui-devkit/package.json

+ 18 - 0
CHANGELOG.md

@@ -1,3 +1,21 @@
+## <small>0.15.1 (2020-09-09)</small>
+
+
+#### Features
+
+* **admin-ui** Customer address editor opens in modal ([0a4d460](https://github.com/vendure-ecommerce/vendure/commit/0a4d460))
+* **create** Make distinction between MySQL & MariaDB ([a31bbf8](https://github.com/vendure-ecommerce/vendure/commit/a31bbf8))
+
+#### Fixes
+
+* **admin-ui** Allow removing last item from ProductSelectorFromInput ([21db8cf](https://github.com/vendure-ecommerce/vendure/commit/21db8cf))
+* **admin-ui** Correctly update product list after deletion ([5587144](https://github.com/vendure-ecommerce/vendure/commit/5587144)), closes [#453](https://github.com/vendure-ecommerce/vendure/issues/453)
+* **admin-ui** Display custom fields in Address form ([f074f65](https://github.com/vendure-ecommerce/vendure/commit/f074f65)), closes [#455](https://github.com/vendure-ecommerce/vendure/issues/455)
+* **core** Add resolver for Product.facetValues ([163a32f](https://github.com/vendure-ecommerce/vendure/commit/163a32f)), closes [#449](https://github.com/vendure-ecommerce/vendure/issues/449)
+* **core** Add warning for list defaults in mysql ([d47becc](https://github.com/vendure-ecommerce/vendure/commit/d47becc))
+* **core** Correctly parse fragments defined before operations ([44a9ab9](https://github.com/vendure-ecommerce/vendure/commit/44a9ab9)), closes [#459](https://github.com/vendure-ecommerce/vendure/issues/459)
+* **core** Fix only_full_group_by issues in MySQL search ([188cfaa](https://github.com/vendure-ecommerce/vendure/commit/188cfaa))
+
 ## 0.15.0 (2020-08-27)
 ## 0.15.0 (2020-08-27)
 
 
 
 

+ 1 - 1
lerna.json

@@ -2,7 +2,7 @@
   "packages": [
   "packages": [
     "packages/*"
     "packages/*"
   ],
   ],
-  "version": "0.15.0",
+  "version": "0.15.1",
   "npmClient": "yarn",
   "npmClient": "yarn",
   "useWorkspaces": true,
   "useWorkspaces": true,
   "command": {
   "command": {

+ 2 - 2
packages/admin-ui-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/admin-ui-plugin",
   "name": "@vendure/admin-ui-plugin",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "types": "lib/index.d.ts",
   "files": [
   "files": [
@@ -20,7 +20,7 @@
     "@types/express": "^4.0.39",
     "@types/express": "^4.0.39",
     "@types/fs-extra": "^8.0.1",
     "@types/fs-extra": "^8.0.1",
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "express": "^4.16.4",
     "express": "^4.16.4",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "typescript": "3.8.3"
     "typescript": "3.8.3"

+ 1 - 1
packages/admin-ui/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/admin-ui",
   "name": "@vendure/admin-ui",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "license": "MIT",
   "license": "MIT",
   "scripts": {
   "scripts": {
     "ng": "ng",
     "ng": "ng",

+ 3 - 0
packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts

@@ -123,6 +123,9 @@ export class ProductListComponent
             })
             })
             .pipe(
             .pipe(
                 switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),
                 switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),
+                // Short delay to allow the product to be removed from the search index before
+                // refreshing.
+                delay(500),
             )
             )
             .subscribe(
             .subscribe(
                 () => {
                 () => {

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/version.ts

@@ -1,2 +1,2 @@
 // Auto-generated by the set-version.js script.
 // Auto-generated by the set-version.js script.
-export const ADMIN_UI_VERSION = '0.15.0';
+export const ADMIN_UI_VERSION = '0.15.1';

+ 4 - 45
packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.html

@@ -17,53 +17,12 @@
     </div>
     </div>
     <div class="card-block">
     <div class="card-block">
         <div class="card-text">
         <div class="card-text">
-            <vdr-formatted-address [address]="address" *ngIf="!editing"></vdr-formatted-address>
-            <form [formGroup]="addressForm" *ngIf="editing">
-                <clr-input-container>
-                    <label>{{ 'customer.full-name' | translate }}</label>
-                    <input formControlName="fullName" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.street-line-1' | translate }}</label>
-                    <input formControlName="streetLine1" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.street-line-2' | translate }}</label>
-                    <input formControlName="streetLine2" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.city' | translate }}</label>
-                    <input formControlName="city" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.province' | translate }}</label>
-                    <input formControlName="province" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.postal-code' | translate }}</label>
-                    <input formControlName="postalCode" type="text" clrInput />
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.country' | translate }}</label>
-                    <select name="countryCode" formControlName="countryCode" clrInput clrSelect>
-                        <option *ngFor="let country of availableCountries" [value]="country.code">
-                            {{ country.name }}
-                        </option>
-                    </select>
-                </clr-input-container>
-                <clr-input-container>
-                    <label>{{ 'customer.phone-number' | translate }}</label>
-                    <input formControlName="phoneNumber" type="text" clrInput />
-                </clr-input-container>
-            </form>
+            <vdr-formatted-address [address]="address"></vdr-formatted-address>
         </div>
         </div>
     </div>
     </div>
     <div class="card-footer">
     <div class="card-footer">
         <vdr-entity-info [entity]="address"></vdr-entity-info>
         <vdr-entity-info [entity]="address"></vdr-entity-info>
-        <button class="btn btn-sm btn-link" *ngIf="editing" (click)="editing = false">
-            {{ 'common.done' | translate }}
-        </button>
-        <button class="btn btn-sm btn-link" *ngIf="!editing" (click)="editing = true">
+        <button class="btn btn-sm btn-link" (click)="editAddress()">
             {{ 'common.edit' | translate }}
             {{ 'common.edit' | translate }}
         </button>
         </button>
         <vdr-dropdown>
         <vdr-dropdown>
@@ -75,7 +34,7 @@
                 <button
                 <button
                     vdrDropdownItem
                     vdrDropdownItem
                     class="button"
                     class="button"
-                    [disabled]="isDefaultShipping || editing"
+                    [disabled]="isDefaultShipping"
                     (click)="setAsDefaultShippingAddress()"
                     (click)="setAsDefaultShippingAddress()"
                 >
                 >
                     {{ 'customer.set-as-default-shipping-address' | translate }}
                     {{ 'customer.set-as-default-shipping-address' | translate }}
@@ -83,7 +42,7 @@
                 <button
                 <button
                     vdrDropdownItem
                     vdrDropdownItem
                     class="button"
                     class="button"
-                    [disabled]="isDefaultBilling || editing"
+                    [disabled]="isDefaultBilling"
                     (click)="setAsDefaultBillingAddress()"
                     (click)="setAsDefaultBillingAddress()"
                 >
                 >
                     {{ 'customer.set-as-default-billing-address' | translate }}
                     {{ 'customer.set-as-default-billing-address' | translate }}

+ 31 - 4
packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.ts

@@ -1,7 +1,16 @@
-import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import {
+    ChangeDetectionStrategy,
+    ChangeDetectorRef,
+    Component,
+    EventEmitter,
+    Input,
+    OnInit,
+    Output,
+} from '@angular/core';
 import { FormControl, FormGroup } from '@angular/forms';
 import { FormControl, FormGroup } from '@angular/forms';
+import { CustomFieldConfig, GetAvailableCountries, ModalService } from '@vendure/admin-ui/core';
 
 
-import { GetAvailableCountries } from '@vendure/admin-ui/core';
+import { AddressDetailDialogComponent } from '../address-detail-dialog/address-detail-dialog.component';
 
 
 @Component({
 @Component({
     selector: 'vdr-address-card',
     selector: 'vdr-address-card',
@@ -10,18 +19,20 @@ import { GetAvailableCountries } from '@vendure/admin-ui/core';
     changeDetection: ChangeDetectionStrategy.OnPush,
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
 })
 export class AddressCardComponent implements OnInit {
 export class AddressCardComponent implements OnInit {
-    editing = false;
     @Input() addressForm: FormGroup;
     @Input() addressForm: FormGroup;
+    @Input() customFields: CustomFieldConfig;
     @Input() availableCountries: GetAvailableCountries.Items[] = [];
     @Input() availableCountries: GetAvailableCountries.Items[] = [];
     @Input() isDefaultBilling: string;
     @Input() isDefaultBilling: string;
     @Input() isDefaultShipping: string;
     @Input() isDefaultShipping: string;
     @Output() setAsDefaultShipping = new EventEmitter<string>();
     @Output() setAsDefaultShipping = new EventEmitter<string>();
     @Output() setAsDefaultBilling = new EventEmitter<string>();
     @Output() setAsDefaultBilling = new EventEmitter<string>();
 
 
+    constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}
+
     ngOnInit(): void {
     ngOnInit(): void {
         const streetLine1 = this.addressForm.get('streetLine1') as FormControl;
         const streetLine1 = this.addressForm.get('streetLine1') as FormControl;
         if (!streetLine1.value) {
         if (!streetLine1.value) {
-            this.editing = true;
+            this.editAddress();
         }
         }
     }
     }
 
 
@@ -42,4 +53,20 @@ export class AddressCardComponent implements OnInit {
         this.setAsDefaultShipping.emit(this.addressForm.value.id);
         this.setAsDefaultShipping.emit(this.addressForm.value.id);
         this.addressForm.markAsDirty();
         this.addressForm.markAsDirty();
     }
     }
+
+    editAddress() {
+        this.modalService
+            .fromComponent(AddressDetailDialogComponent, {
+                locals: {
+                    addressForm: this.addressForm,
+                    customFields: this.customFields,
+                    availableCountries: this.availableCountries,
+                },
+                size: 'md',
+                closable: true,
+            })
+            .subscribe(() => {
+                this.changeDetector.markForCheck();
+            });
+    }
 }
 }

+ 84 - 0
packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.html

@@ -0,0 +1,84 @@
+<ng-template vdrDialogTitle>
+    <span *ngIf="addressForm.get('streetLine1')?.value as streetLine1">{{ streetLine1 }},</span>
+    <span *ngIf="addressForm.get('countryCode')?.value as countryCode"> {{ countryCode }}</span>
+</ng-template>
+
+<form [formGroup]="addressForm">
+    <clr-input-container>
+        <label>{{ 'customer.full-name' | translate }}</label>
+        <input formControlName="fullName" type="text" clrInput />
+    </clr-input-container>
+
+    <div class="clr-row">
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.street-line-1' | translate }}</label>
+                <input formControlName="streetLine1" type="text" clrInput />
+            </clr-input-container>
+        </div>
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.street-line-2' | translate }}</label>
+                <input formControlName="streetLine2" type="text" clrInput />
+            </clr-input-container>
+        </div>
+    </div>
+    <div class="clr-row">
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.city' | translate }}</label>
+                <input formControlName="city" type="text" clrInput />
+            </clr-input-container>
+        </div>
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.province' | translate }}</label>
+                <input formControlName="province" type="text" clrInput />
+            </clr-input-container>
+        </div>
+    </div>
+    <div class="clr-row">
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.postal-code' | translate }}</label>
+                <input formControlName="postalCode" type="text" clrInput />
+            </clr-input-container>
+        </div>
+        <div class="clr-col-md-4">
+            <clr-input-container>
+                <label>{{ 'customer.country' | translate }}</label>
+                <select name="countryCode" formControlName="countryCode" clrInput clrSelect>
+                    <option *ngFor="let country of availableCountries" [value]="country.code">
+                        {{ country.name }}
+                    </option>
+                </select>
+            </clr-input-container>
+        </div>
+    </div>
+    <clr-input-container>
+        <label>{{ 'customer.phone-number' | translate }}</label>
+        <input formControlName="phoneNumber" type="text" clrInput />
+    </clr-input-container>
+    <section formGroupName="customFields" *ngIf="addressForm.get('customFields') as customFieldsGroup">
+        <label>{{ 'common.custom-fields' | translate }}</label>
+        <ng-container *ngFor="let customField of customFields">
+            <vdr-custom-field-control
+                entityName="Facet"
+                [customFieldsFormGroup]="customFieldsGroup"
+                [customField]="customField"
+            ></vdr-custom-field-control>
+        </ng-container>
+    </section>
+</form>
+
+<ng-template vdrDialogButtons>
+    <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
+    <button
+        type="submit"
+        (click)="save()"
+        [disabled]="!addressForm.valid || !addressForm.touched"
+        class="btn btn-primary"
+    >
+        {{ 'common.update' | translate }}
+    </button>
+</ng-template>

+ 5 - 0
packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.scss

@@ -0,0 +1,5 @@
+@import "variables";
+
+clr-input-container {
+    margin-bottom: 12px;
+}

+ 30 - 0
packages/admin-ui/src/lib/customer/src/components/address-detail-dialog/address-detail-dialog.component.ts

@@ -0,0 +1,30 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
+import { FormGroup } from '@angular/forms';
+import { CustomFieldConfig, Dialog, GetAvailableCountries } from '@vendure/admin-ui/core';
+
+@Component({
+    selector: 'vdr-address-detail-dialog',
+    templateUrl: './address-detail-dialog.component.html',
+    styleUrls: ['./address-detail-dialog.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class AddressDetailDialogComponent implements Dialog<FormGroup>, OnInit {
+    addressForm: FormGroup;
+    customFields: CustomFieldConfig;
+    availableCountries: GetAvailableCountries.Items[] = [];
+    resolveWith: (result?: FormGroup) => void;
+
+    constructor(private changeDetector: ChangeDetectorRef) {}
+
+    ngOnInit() {
+        this.addressForm.valueChanges.subscribe(() => this.changeDetector.markForCheck());
+    }
+
+    cancel() {
+        this.resolveWith();
+    }
+
+    save() {
+        this.resolveWith(this.addressForm);
+    }
+}

+ 1 - 0
packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.html

@@ -111,6 +111,7 @@
             [isDefaultBilling]="defaultBillingAddressId === addressForm.value.id"
             [isDefaultBilling]="defaultBillingAddressId === addressForm.value.id"
             [isDefaultShipping]="defaultShippingAddressId === addressForm.value.id"
             [isDefaultShipping]="defaultShippingAddressId === addressForm.value.id"
             [addressForm]="addressForm"
             [addressForm]="addressForm"
+            [customFields]="addressCustomFields"
             (setAsDefaultBilling)="setDefaultBillingAddressId($event)"
             (setAsDefaultBilling)="setDefaultBillingAddressId($event)"
             (setAsDefaultShipping)="setDefaultShippingAddressId($event)"
             (setAsDefaultShipping)="setDefaultShippingAddressId($event)"
         ></vdr-address-card>
         ></vdr-address-card>

+ 20 - 3
packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.ts

@@ -49,6 +49,7 @@ export class CustomerDetailComponent extends BaseDetailComponent<CustomerWithOrd
     implements OnInit, OnDestroy {
     implements OnInit, OnDestroy {
     detailForm: FormGroup;
     detailForm: FormGroup;
     customFields: CustomFieldConfig[];
     customFields: CustomFieldConfig[];
+    addressCustomFields: CustomFieldConfig[];
     availableCountries$: Observable<GetAvailableCountries.Items[]>;
     availableCountries$: Observable<GetAvailableCountries.Items[]>;
     orders$: Observable<GetCustomer.Items[]>;
     orders$: Observable<GetCustomer.Items[]>;
     ordersCount$: Observable<number>;
     ordersCount$: Observable<number>;
@@ -74,6 +75,7 @@ export class CustomerDetailComponent extends BaseDetailComponent<CustomerWithOrd
         super(route, router, serverConfigService, dataService);
         super(route, router, serverConfigService, dataService);
 
 
         this.customFields = this.getCustomFieldConfig('Customer');
         this.customFields = this.getCustomFieldConfig('Customer');
+        this.addressCustomFields = this.getCustomFieldConfig('Address');
         this.detailForm = this.formBuilder.group({
         this.detailForm = this.formBuilder.group({
             customer: this.formBuilder.group({
             customer: this.formBuilder.group({
                 title: '',
                 title: '',
@@ -245,6 +247,7 @@ export class CustomerDetailComponent extends BaseDetailComponent<CustomerWithOrd
                                     phoneNumber: address.phoneNumber,
                                     phoneNumber: address.phoneNumber,
                                     defaultShippingAddress: this.defaultShippingAddressId === address.id,
                                     defaultShippingAddress: this.defaultShippingAddressId === address.id,
                                     defaultBillingAddress: this.defaultBillingAddressId === address.id,
                                     defaultBillingAddress: this.defaultBillingAddressId === address.id,
+                                    customFields: address.customFields,
                                 };
                                 };
                                 if (!address.id) {
                                 if (!address.id) {
                                     saveOperations.push(
                                     saveOperations.push(
@@ -403,15 +406,29 @@ export class CustomerDetailComponent extends BaseDetailComponent<CustomerWithOrd
         if (entity.addresses) {
         if (entity.addresses) {
             const addressesArray = new FormArray([]);
             const addressesArray = new FormArray([]);
             for (const address of entity.addresses) {
             for (const address of entity.addresses) {
-                addressesArray.push(
-                    this.formBuilder.group({ ...address, countryCode: address.country.code }),
-                );
+                const { customFields, ...rest } = address as any;
+                const addressGroup = this.formBuilder.group({
+                    ...rest,
+                    countryCode: address.country.code,
+                });
+                addressesArray.push(addressGroup);
                 if (address.defaultShippingAddress) {
                 if (address.defaultShippingAddress) {
                     this.defaultShippingAddressId = address.id;
                     this.defaultShippingAddressId = address.id;
                 }
                 }
                 if (address.defaultBillingAddress) {
                 if (address.defaultBillingAddress) {
                     this.defaultBillingAddressId = address.id;
                     this.defaultBillingAddressId = address.id;
                 }
                 }
+
+                if (this.addressCustomFields.length) {
+                    const customFieldsGroup = this.formBuilder.group({});
+                    for (const fieldDef of this.addressCustomFields) {
+                        const key = fieldDef.name;
+                        const value = (address as any).customFields?.[key];
+                        const control = new FormControl(value);
+                        customFieldsGroup.addControl(key, control);
+                    }
+                    addressGroup.addControl('customFields', customFieldsGroup);
+                }
             }
             }
             this.detailForm.setControl('addresses', addressesArray);
             this.detailForm.setControl('addresses', addressesArray);
         }
         }

+ 2 - 0
packages/admin-ui/src/lib/customer/src/customer.module.ts

@@ -4,6 +4,7 @@ import { SharedModule } from '@vendure/admin-ui/core';
 
 
 import { AddCustomerToGroupDialogComponent } from './components/add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 import { AddCustomerToGroupDialogComponent } from './components/add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 import { AddressCardComponent } from './components/address-card/address-card.component';
 import { AddressCardComponent } from './components/address-card/address-card.component';
+import { AddressDetailDialogComponent } from './components/address-detail-dialog/address-detail-dialog.component';
 import { CustomerDetailComponent } from './components/customer-detail/customer-detail.component';
 import { CustomerDetailComponent } from './components/customer-detail/customer-detail.component';
 import { CustomerGroupDetailDialogComponent } from './components/customer-group-detail-dialog/customer-group-detail-dialog.component';
 import { CustomerGroupDetailDialogComponent } from './components/customer-group-detail-dialog/customer-group-detail-dialog.component';
 import { CustomerGroupListComponent } from './components/customer-group-list/customer-group-list.component';
 import { CustomerGroupListComponent } from './components/customer-group-list/customer-group-list.component';
@@ -27,6 +28,7 @@ import { customerRoutes } from './customer.routes';
         CustomerGroupMemberListComponent,
         CustomerGroupMemberListComponent,
         SelectCustomerGroupDialogComponent,
         SelectCustomerGroupDialogComponent,
         CustomerHistoryComponent,
         CustomerHistoryComponent,
+        AddressDetailDialogComponent,
     ],
     ],
     exports: [AddressCardComponent],
     exports: [AddressCardComponent],
 })
 })

+ 1 - 0
packages/admin-ui/src/lib/customer/src/public_api.ts

@@ -1,6 +1,7 @@
 // This file was generated by the build-public-api.ts script
 // This file was generated by the build-public-api.ts script
 export * from './components/add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 export * from './components/add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 export * from './components/address-card/address-card.component';
 export * from './components/address-card/address-card.component';
+export * from './components/address-detail-dialog/address-detail-dialog.component';
 export * from './components/customer-detail/customer-detail.component';
 export * from './components/customer-detail/customer-detail.component';
 export * from './components/customer-group-detail-dialog/customer-group-detail-dialog.component';
 export * from './components/customer-group-detail-dialog/customer-group-detail-dialog.component';
 export * from './components/customer-group-list/customer-group-list.component';
 export * from './components/customer-group-list/customer-group-list.component';

+ 2 - 2
packages/asset-server-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/asset-server-plugin",
   "name": "@vendure/asset-server-plugin",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "types": "lib/index.d.ts",
   "files": [
   "files": [
@@ -23,7 +23,7 @@
     "@types/node-fetch": "^2.5.4",
     "@types/node-fetch": "^2.5.4",
     "@types/sharp": "^0.24.0",
     "@types/sharp": "^0.24.0",
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "aws-sdk": "^2.670.0",
     "aws-sdk": "^2.670.0",
     "express": "^4.16.4",
     "express": "^4.16.4",
     "node-fetch": "^2.6.0",
     "node-fetch": "^2.6.0",

+ 28 - 0
packages/core/e2e/asset.e2e-spec.ts

@@ -14,6 +14,7 @@ import {
     DeleteAsset,
     DeleteAsset,
     DeletionResult,
     DeletionResult,
     GetAsset,
     GetAsset,
+    GetAssetFragmentFirst,
     GetAssetList,
     GetAssetList,
     GetProductWithVariants,
     GetProductWithVariants,
     SortOrder,
     SortOrder,
@@ -121,6 +122,20 @@ describe('Asset resolver', () => {
         });
         });
     });
     });
 
 
+    /**
+     * https://github.com/vendure-ecommerce/vendure/issues/459
+     */
+    it('transforms URL when fragment defined before query (GH issue #459)', async () => {
+        const { asset } = await adminClient.query<
+            GetAssetFragmentFirst.Query,
+            GetAssetFragmentFirst.Variables
+        >(GET_ASSET_FRAGMENT_FIRST, {
+            id: firstAssetId,
+        });
+
+        expect(asset?.preview).toBe('test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg');
+    });
+
     describe('createAssets', () => {
     describe('createAssets', () => {
         it('permitted types by mime type', async () => {
         it('permitted types by mime type', async () => {
             const filesToUpload = [
             const filesToUpload = [
@@ -343,6 +358,19 @@ export const GET_ASSET = gql`
     ${ASSET_FRAGMENT}
     ${ASSET_FRAGMENT}
 `;
 `;
 
 
+export const GET_ASSET_FRAGMENT_FIRST = gql`
+    fragment AssetFragFirst on Asset {
+        id
+        preview
+    }
+
+    query GetAssetFragmentFirst($id: ID!) {
+        asset(id: $id) {
+            ...AssetFragFirst
+        }
+    }
+`;
+
 export const CREATE_ASSETS = gql`
 export const CREATE_ASSETS = gql`
     mutation CreateAssets($input: [CreateAssetInput!]!) {
     mutation CreateAssets($input: [CreateAssetInput!]!) {
         createAssets(input: $input) {
         createAssets(input: $input) {

+ 20 - 0
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -3753,6 +3753,16 @@ export type GetAssetQuery = { __typename?: 'Query' } & {
     asset?: Maybe<{ __typename?: 'Asset' } & Pick<Asset, 'width' | 'height'> & AssetFragment>;
     asset?: Maybe<{ __typename?: 'Asset' } & Pick<Asset, 'width' | 'height'> & AssetFragment>;
 };
 };
 
 
+export type AssetFragFirstFragment = { __typename?: 'Asset' } & Pick<Asset, 'id' | 'preview'>;
+
+export type GetAssetFragmentFirstQueryVariables = {
+    id: Scalars['ID'];
+};
+
+export type GetAssetFragmentFirstQuery = { __typename?: 'Query' } & {
+    asset?: Maybe<{ __typename?: 'Asset' } & AssetFragFirstFragment>;
+};
+
 export type CreateAssetsMutationVariables = {
 export type CreateAssetsMutationVariables = {
     input: Array<CreateAssetInput>;
     input: Array<CreateAssetInput>;
 };
 };
@@ -6055,6 +6065,16 @@ export namespace GetAsset {
     export type Asset = AssetFragment;
     export type Asset = AssetFragment;
 }
 }
 
 
+export namespace AssetFragFirst {
+    export type Fragment = AssetFragFirstFragment;
+}
+
+export namespace GetAssetFragmentFirst {
+    export type Variables = GetAssetFragmentFirstQueryVariables;
+    export type Query = GetAssetFragmentFirstQuery;
+    export type Asset = AssetFragFirstFragment;
+}
+
 export namespace CreateAssets {
 export namespace CreateAssets {
     export type Variables = CreateAssetsMutationVariables;
     export type Variables = CreateAssetsMutationVariables;
     export type Mutation = CreateAssetsMutation;
     export type Mutation = CreateAssetsMutation;

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/core",
   "name": "@vendure/core",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "description": "A modern, headless ecommerce framework",
   "description": "A modern, headless ecommerce framework",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",

+ 3 - 0
packages/core/src/api/common/graphql-value-transformer.ts

@@ -114,6 +114,9 @@ export class GraphqlValueTransformer {
                         currentNode = currentNode.parent;
                         currentNode = currentNode.parent;
                     }
                     }
                 }
                 }
+                if (node.kind === 'FragmentDefinition') {
+                    currentNode = rootNode;
+                }
             },
             },
         };
         };
         for (const operation of document.definitions) {
         for (const operation of document.definitions) {

+ 2 - 2
packages/create/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/create",
   "name": "@vendure/create",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "license": "MIT",
   "license": "MIT",
   "bin": {
   "bin": {
     "create": "./index.js"
     "create": "./index.js"
@@ -26,7 +26,7 @@
     "@types/handlebars": "^4.1.0",
     "@types/handlebars": "^4.1.0",
     "@types/listr": "^0.14.0",
     "@types/listr": "^0.14.0",
     "@types/semver": "^6.0.0",
     "@types/semver": "^6.0.0",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "ts-node": "^8.4.1",
     "ts-node": "^8.4.1",
     "typescript": "3.8.3"
     "typescript": "3.8.3"

+ 8 - 8
packages/dev-server/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "dev-server",
   "name": "dev-server",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "main": "index.js",
   "main": "index.js",
   "license": "MIT",
   "license": "MIT",
   "private": true,
   "private": true,
@@ -14,18 +14,18 @@
     "load-test:100k": "node -r ts-node/register load-testing/run-load-test.ts 100000"
     "load-test:100k": "node -r ts-node/register load-testing/run-load-test.ts 100000"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@vendure/admin-ui-plugin": "^0.15.0",
-    "@vendure/asset-server-plugin": "^0.15.0",
+    "@vendure/admin-ui-plugin": "^0.15.1",
+    "@vendure/asset-server-plugin": "^0.15.1",
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
-    "@vendure/core": "^0.15.0",
-    "@vendure/elasticsearch-plugin": "^0.15.0",
-    "@vendure/email-plugin": "^0.15.0",
+    "@vendure/core": "^0.15.1",
+    "@vendure/elasticsearch-plugin": "^0.15.1",
+    "@vendure/email-plugin": "^0.15.1",
     "typescript": "3.8.3"
     "typescript": "3.8.3"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@types/csv-stringify": "^3.1.0",
     "@types/csv-stringify": "^3.1.0",
-    "@vendure/testing": "^0.15.0",
-    "@vendure/ui-devkit": "^0.15.0",
+    "@vendure/testing": "^0.15.1",
+    "@vendure/ui-devkit": "^0.15.1",
     "concurrently": "^5.0.0",
     "concurrently": "^5.0.0",
     "csv-stringify": "^5.3.3"
     "csv-stringify": "^5.3.3"
   }
   }

+ 2 - 2
packages/elasticsearch-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/elasticsearch-plugin",
   "name": "@vendure/elasticsearch-plugin",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "license": "MIT",
   "license": "MIT",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "types": "lib/index.d.ts",
@@ -23,7 +23,7 @@
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "typescript": "3.8.3"
     "typescript": "3.8.3"
   }
   }

+ 2 - 2
packages/email-plugin/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/email-plugin",
   "name": "@vendure/email-plugin",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "license": "MIT",
   "license": "MIT",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "types": "lib/index.d.ts",
   "types": "lib/index.d.ts",
@@ -34,7 +34,7 @@
     "@types/mjml": "^4.0.2",
     "@types/mjml": "^4.0.2",
     "@types/nodemailer": "^6.4.0",
     "@types/nodemailer": "^6.4.0",
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "typescript": "3.8.3"
     "typescript": "3.8.3"
   }
   }

+ 2 - 2
packages/testing/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/testing",
   "name": "@vendure/testing",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "description": "End-to-end testing tools for Vendure projects",
   "description": "End-to-end testing tools for Vendure projects",
   "keywords": [
   "keywords": [
     "vendure",
     "vendure",
@@ -44,7 +44,7 @@
   "devDependencies": {
   "devDependencies": {
     "@types/mysql": "^2.15.8",
     "@types/mysql": "^2.15.8",
     "@types/pg": "^7.14.1",
     "@types/pg": "^7.14.1",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "mysql": "^2.17.1",
     "mysql": "^2.17.1",
     "pg": "^7.17.1",
     "pg": "^7.17.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",

+ 3 - 3
packages/ui-devkit/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@vendure/ui-devkit",
   "name": "@vendure/ui-devkit",
-  "version": "0.15.0",
+  "version": "0.15.1",
   "description": "A library for authoring Vendure Admin UI extensions",
   "description": "A library for authoring Vendure Admin UI extensions",
   "keywords": [
   "keywords": [
     "vendure",
     "vendure",
@@ -39,7 +39,7 @@
     "@angular/cli": "^9.0.5",
     "@angular/cli": "^9.0.5",
     "@angular/compiler": "^9.0.6",
     "@angular/compiler": "^9.0.6",
     "@angular/compiler-cli": "^9.0.6",
     "@angular/compiler-cli": "^9.0.6",
-    "@vendure/admin-ui": "^0.15.0",
+    "@vendure/admin-ui": "^0.15.1",
     "@vendure/common": "^0.15.0",
     "@vendure/common": "^0.15.0",
     "chalk": "^3.0.0",
     "chalk": "^3.0.0",
     "chokidar": "^3.3.1",
     "chokidar": "^3.3.1",
@@ -51,7 +51,7 @@
     "@rollup/plugin-node-resolve": "^7.1.1",
     "@rollup/plugin-node-resolve": "^7.1.1",
     "@types/fs-extra": "^8.1.0",
     "@types/fs-extra": "^8.1.0",
     "@types/glob": "^7.1.1",
     "@types/glob": "^7.1.1",
-    "@vendure/core": "^0.15.0",
+    "@vendure/core": "^0.15.1",
     "rimraf": "^3.0.0",
     "rimraf": "^3.0.0",
     "rollup": "^2.2.0",
     "rollup": "^2.2.0",
     "rollup-plugin-terser": "^5.3.0",
     "rollup-plugin-terser": "^5.3.0",