Browse Source

feat(admin-ui): Implement deletion of ProductVariants

Michael Bromley 6 years ago
parent
commit
bcc26625cc

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

@@ -155,6 +155,7 @@
                         (updateProductOption)="updateProductOption($event)"
                         (selectionChange)="selectedVariantIds = $event"
                         (selectFacetValueClick)="selectVariantFacetValue($event)"
+                        (deleteVariant)="deleteVariant($event)"
                     ></vdr-product-variants-list>
                 </section>
             </clr-tab-content>

+ 30 - 2
admin-ui/src/app/catalog/components/product-detail/product-detail.component.ts

@@ -2,8 +2,8 @@ import { Location } from '@angular/common';
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
 import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
-import { combineLatest, merge, Observable } from 'rxjs';
-import { distinctUntilChanged, map, mergeMap, take, withLatestFrom } from 'rxjs/operators';
+import { combineLatest, EMPTY, merge, Observable } from 'rxjs';
+import { distinctUntilChanged, map, mergeMap, switchMap, take, withLatestFrom } from 'rxjs/operators';
 import { normalizeString } from 'shared/normalize-string';
 import { CustomFieldConfig } from 'shared/shared-types';
 import { notNullOrUndefined } from 'shared/shared-utils';
@@ -253,6 +253,34 @@ export class ProductDetailComponent extends BaseDetailComponent<ProductWithVaria
         );
     }
 
+    deleteVariant(id: string) {
+        this.modalService
+            .dialog({
+                title: _('catalog.confirm-delete-product-variant'),
+                buttons: [
+                    { type: 'seconday', label: _('common.cancel') },
+                    { type: 'danger', label: _('common.delete'), returnValue: true },
+                ],
+            })
+            .pipe(
+                switchMap(response =>
+                    response ? this.productDetailService.deleteProductVariant(id, this.id) : EMPTY,
+                ),
+            )
+            .subscribe(
+                () => {
+                    this.notificationService.success(_('common.notify-delete-success'), {
+                        entity: 'ProductVariant',
+                    });
+                },
+                err => {
+                    this.notificationService.error(_('common.notify-delete-error'), {
+                        entity: 'ProductVariant',
+                    });
+                },
+            );
+    }
+
     private displayFacetValueModal(): Observable<string[] | undefined> {
         return this.productDetailService.getFacets().pipe(
             mergeMap(facets =>

+ 17 - 1
admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.html

@@ -28,11 +28,27 @@
                         </clr-input-container>
                     </vdr-title-input>
                 </div>
-                <div>
+                <div class="right-controls">
                     <clr-toggle-wrapper>
                         <input type="checkbox" clrToggle name="enabled" formControlName="enabled" />
                         <label>{{ 'common.enabled' | translate }}</label>
                     </clr-toggle-wrapper>
+                    <vdr-dropdown>
+                        <button class="icon-button" vdrDropdownTrigger>
+                            <clr-icon shape="ellipsis-vertical"></clr-icon>
+                        </button>
+                        <vdr-dropdown-menu vdrPosition="bottom-right">
+                            <button
+                                type="button"
+                                class="delete-button"
+                                (click)="deleteVariantClick(variant.id)"
+                                vdrDropdownItem
+                            >
+                                <clr-icon shape="trash" class="is-danger"></clr-icon>
+                                {{ 'common.delete' | translate }}
+                            </button>
+                        </vdr-dropdown-menu>
+                    </vdr-dropdown>
                 </div>
             </div>
             <div class="card-block">

+ 4 - 0
admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.scss

@@ -59,6 +59,10 @@
         }
     }
 
+    .right-controls {
+        display: flex;
+    }
+
     .variant-form-input-row {
         display: flex;
         flex-wrap: wrap;

+ 5 - 0
admin-ui/src/app/catalog/components/product-variants-list/product-variants-list.component.ts

@@ -48,6 +48,7 @@ export class ProductVariantsListComponent implements OnChanges, OnInit, OnDestro
     @Output() selectionChange = new EventEmitter<string[]>();
     @Output() selectFacetValueClick = new EventEmitter<string[]>();
     @Output() updateProductOption = new EventEmitter<UpdateProductOptionInput>();
+    @Output() deleteVariant = new EventEmitter<string>();
     selectedVariantIds: string[] = [];
     private facetValues: FacetValue.Fragment[];
     private formSubscription: Subscription;
@@ -163,6 +164,10 @@ export class ProductVariantsListComponent implements OnChanges, OnInit, OnDestro
             });
     }
 
+    deleteVariantClick(id: string) {
+        this.deleteVariant.emit(id);
+    }
+
     private getFacetValueIds(index: number): string[] {
         const formValue: VariantFormValue = this.formArray.at(index).value;
         return formValue.facetValueIds;

+ 15 - 2
admin-ui/src/app/catalog/providers/product-detail.service.ts

@@ -1,11 +1,12 @@
 import { Injectable } from '@angular/core';
-import { BehaviorSubject, forkJoin, Observable, of } from 'rxjs';
-import { map, mergeMap, shareReplay, skip } from 'rxjs/operators';
+import { BehaviorSubject, forkJoin, Observable, of, throwError } from 'rxjs';
+import { map, mergeMap, shareReplay, skip, switchMap } from 'rxjs/operators';
 import { normalizeString } from 'shared/normalize-string';
 
 import {
     CreateProductInput,
     CreateProductVariantInput,
+    DeletionResult,
     FacetWithValues,
     LanguageCode,
     UpdateProductInput,
@@ -145,4 +146,16 @@ export class ProductDetailService {
     updateProductOption(input: UpdateProductOptionInput) {
         return this.dataService.product.updateProductOption(input);
     }
+
+    deleteProductVariant(id: string, productId: string) {
+        return this.dataService.product.deleteProductVariant(id).pipe(
+            switchMap(result => {
+                if (result.deleteProductVariant.result === DeletionResult.DELETED) {
+                    return this.dataService.product.getProduct(productId).single$;
+                } else {
+                    return throwError(result.deleteProductVariant.message);
+                }
+            }),
+        );
+    }
 }

+ 183 - 170
admin-ui/src/app/common/generated-types.ts

@@ -1553,32 +1553,18 @@ export type Mutation = {
   assignRoleToAdministrator: Administrator,
   /** Create a new Asset */
   createAssets: Array<Asset>,
-  login: LoginResult,
-  logout: Scalars['Boolean'],
-  /** Create a new Channel */
-  createChannel: Channel,
-  /** Update an existing Channel */
-  updateChannel: Channel,
   /** Create a new Collection */
   createCollection: Collection,
   /** Update an existing Collection */
   updateCollection: Collection,
   /** Move a Collection to a different parent or index */
   moveCollection: Collection,
-  /** Create a new Country */
-  createCountry: Country,
-  /** Update an existing Country */
-  updateCountry: Country,
-  /** Delete a Country */
-  deleteCountry: DeletionResponse,
-  /** Create a new CustomerGroup */
-  createCustomerGroup: CustomerGroup,
-  /** Update an existing CustomerGroup */
-  updateCustomerGroup: CustomerGroup,
-  /** Add Customers to a CustomerGroup */
-  addCustomersToGroup: CustomerGroup,
-  /** Remove Customers from a CustomerGroup */
-  removeCustomersFromGroup: CustomerGroup,
+  /** Create a new Channel */
+  createChannel: Channel,
+  /** Update an existing Channel */
+  updateChannel: Channel,
+  login: LoginResult,
+  logout: Scalars['Boolean'],
   /** Create a new Customer. If a password is provided, a new User will also be created an linked to the Customer. */
   createCustomer: Customer,
   /** Update an existing Customer */
@@ -1591,6 +1577,12 @@ export type Mutation = {
   updateCustomerAddress: Address,
   /** Update an existing Address */
   deleteCustomerAddress: Scalars['Boolean'],
+  /** Create a new Country */
+  createCountry: Country,
+  /** Update an existing Country */
+  updateCountry: Country,
+  /** Delete a Country */
+  deleteCountry: DeletionResponse,
   /** Create a new Facet */
   createFacet: Facet,
   /** Update an existing Facet */
@@ -1603,14 +1595,16 @@ export type Mutation = {
   updateFacetValues: Array<FacetValue>,
   /** Delete one or more FacetValues */
   deleteFacetValues: Array<DeletionResponse>,
-  importProducts?: Maybe<ImportInfo>,
+  /** Create a new CustomerGroup */
+  createCustomerGroup: CustomerGroup,
+  /** Update an existing CustomerGroup */
+  updateCustomerGroup: CustomerGroup,
+  /** Add Customers to a CustomerGroup */
+  addCustomersToGroup: CustomerGroup,
+  /** Remove Customers from a CustomerGroup */
+  removeCustomersFromGroup: CustomerGroup,
   updateGlobalSettings: GlobalSettings,
-  settlePayment: Payment,
-  fulfillOrder: Fulfillment,
-  cancelOrder: Order,
-  refundOrder: Refund,
-  settleRefund: Refund,
-  addNoteToOrder: Order,
+  importProducts?: Maybe<ImportInfo>,
   /** Update an existing PaymentMethod */
   updatePaymentMethod: PaymentMethod,
   /** Create a new ProductOptionGroup */
@@ -1621,7 +1615,12 @@ export type Mutation = {
   createProductOption: ProductOption,
   /** Create a new ProductOption within a ProductOptionGroup */
   updateProductOption: ProductOption,
-  reindex: JobInfo,
+  settlePayment: Payment,
+  fulfillOrder: Fulfillment,
+  cancelOrder: Order,
+  refundOrder: Refund,
+  settleRefund: Refund,
+  addNoteToOrder: Order,
   /** Create a new Product */
   createProduct: Product,
   /** Update an existing Product */
@@ -1641,22 +1640,23 @@ export type Mutation = {
   createPromotion: Promotion,
   updatePromotion: Promotion,
   deletePromotion: DeletionResponse,
-  /** Create a new Role */
-  createRole: Role,
-  /** Update an existing Role */
-  updateRole: Role,
+  reindex: JobInfo,
   /** Create a new ShippingMethod */
   createShippingMethod: ShippingMethod,
   /** Update an existing ShippingMethod */
   updateShippingMethod: ShippingMethod,
-  /** Create a new TaxCategory */
-  createTaxCategory: TaxCategory,
-  /** Update an existing TaxCategory */
-  updateTaxCategory: TaxCategory,
   /** Create a new TaxRate */
   createTaxRate: TaxRate,
   /** Update an existing TaxRate */
   updateTaxRate: TaxRate,
+  /** Create a new Role */
+  createRole: Role,
+  /** Update an existing Role */
+  updateRole: Role,
+  /** Create a new TaxCategory */
+  createTaxCategory: TaxCategory,
+  /** Update an existing TaxCategory */
+  updateTaxCategory: TaxCategory,
   /** Create a new Zone */
   createZone: Zone,
   /** Update an existing Zone */
@@ -1696,23 +1696,6 @@ export type MutationCreateAssetsArgs = {
 };
 
 
-export type MutationLoginArgs = {
-  username: Scalars['String'],
-  password: Scalars['String'],
-  rememberMe?: Maybe<Scalars['Boolean']>
-};
-
-
-export type MutationCreateChannelArgs = {
-  input: CreateChannelInput
-};
-
-
-export type MutationUpdateChannelArgs = {
-  input: UpdateChannelInput
-};
-
-
 export type MutationCreateCollectionArgs = {
   input: CreateCollectionInput
 };
@@ -1728,40 +1711,20 @@ export type MutationMoveCollectionArgs = {
 };
 
 
-export type MutationCreateCountryArgs = {
-  input: CreateCountryInput
-};
-
-
-export type MutationUpdateCountryArgs = {
-  input: UpdateCountryInput
-};
-
-
-export type MutationDeleteCountryArgs = {
-  id: Scalars['ID']
-};
-
-
-export type MutationCreateCustomerGroupArgs = {
-  input: CreateCustomerGroupInput
-};
-
-
-export type MutationUpdateCustomerGroupArgs = {
-  input: UpdateCustomerGroupInput
+export type MutationCreateChannelArgs = {
+  input: CreateChannelInput
 };
 
 
-export type MutationAddCustomersToGroupArgs = {
-  customerGroupId: Scalars['ID'],
-  customerIds: Array<Scalars['ID']>
+export type MutationUpdateChannelArgs = {
+  input: UpdateChannelInput
 };
 
 
-export type MutationRemoveCustomersFromGroupArgs = {
-  customerGroupId: Scalars['ID'],
-  customerIds: Array<Scalars['ID']>
+export type MutationLoginArgs = {
+  username: Scalars['String'],
+  password: Scalars['String'],
+  rememberMe?: Maybe<Scalars['Boolean']>
 };
 
 
@@ -1797,6 +1760,21 @@ export type MutationDeleteCustomerAddressArgs = {
 };
 
 
+export type MutationCreateCountryArgs = {
+  input: CreateCountryInput
+};
+
+
+export type MutationUpdateCountryArgs = {
+  input: UpdateCountryInput
+};
+
+
+export type MutationDeleteCountryArgs = {
+  id: Scalars['ID']
+};
+
+
 export type MutationCreateFacetArgs = {
   input: CreateFacetInput
 };
@@ -1829,43 +1807,35 @@ export type MutationDeleteFacetValuesArgs = {
 };
 
 
-export type MutationImportProductsArgs = {
-  csvFile: Scalars['Upload']
-};
-
-
-export type MutationUpdateGlobalSettingsArgs = {
-  input: UpdateGlobalSettingsInput
-};
-
-
-export type MutationSettlePaymentArgs = {
-  id: Scalars['ID']
+export type MutationCreateCustomerGroupArgs = {
+  input: CreateCustomerGroupInput
 };
 
 
-export type MutationFulfillOrderArgs = {
-  input: FulfillOrderInput
+export type MutationUpdateCustomerGroupArgs = {
+  input: UpdateCustomerGroupInput
 };
 
 
-export type MutationCancelOrderArgs = {
-  input: CancelOrderInput
+export type MutationAddCustomersToGroupArgs = {
+  customerGroupId: Scalars['ID'],
+  customerIds: Array<Scalars['ID']>
 };
 
 
-export type MutationRefundOrderArgs = {
-  input: RefundOrderInput
+export type MutationRemoveCustomersFromGroupArgs = {
+  customerGroupId: Scalars['ID'],
+  customerIds: Array<Scalars['ID']>
 };
 
 
-export type MutationSettleRefundArgs = {
-  input: SettleRefundInput
+export type MutationUpdateGlobalSettingsArgs = {
+  input: UpdateGlobalSettingsInput
 };
 
 
-export type MutationAddNoteToOrderArgs = {
-  input: AddNoteToOrderInput
+export type MutationImportProductsArgs = {
+  csvFile: Scalars['Upload']
 };
 
 
@@ -1894,6 +1864,36 @@ export type MutationUpdateProductOptionArgs = {
 };
 
 
+export type MutationSettlePaymentArgs = {
+  id: Scalars['ID']
+};
+
+
+export type MutationFulfillOrderArgs = {
+  input: FulfillOrderInput
+};
+
+
+export type MutationCancelOrderArgs = {
+  input: CancelOrderInput
+};
+
+
+export type MutationRefundOrderArgs = {
+  input: RefundOrderInput
+};
+
+
+export type MutationSettleRefundArgs = {
+  input: SettleRefundInput
+};
+
+
+export type MutationAddNoteToOrderArgs = {
+  input: AddNoteToOrderInput
+};
+
+
 export type MutationCreateProductArgs = {
   input: CreateProductInput
 };
@@ -1951,43 +1951,43 @@ export type MutationDeletePromotionArgs = {
 };
 
 
-export type MutationCreateRoleArgs = {
-  input: CreateRoleInput
+export type MutationCreateShippingMethodArgs = {
+  input: CreateShippingMethodInput
 };
 
 
-export type MutationUpdateRoleArgs = {
-  input: UpdateRoleInput
+export type MutationUpdateShippingMethodArgs = {
+  input: UpdateShippingMethodInput
 };
 
 
-export type MutationCreateShippingMethodArgs = {
-  input: CreateShippingMethodInput
+export type MutationCreateTaxRateArgs = {
+  input: CreateTaxRateInput
 };
 
 
-export type MutationUpdateShippingMethodArgs = {
-  input: UpdateShippingMethodInput
+export type MutationUpdateTaxRateArgs = {
+  input: UpdateTaxRateInput
 };
 
 
-export type MutationCreateTaxCategoryArgs = {
-  input: CreateTaxCategoryInput
+export type MutationCreateRoleArgs = {
+  input: CreateRoleInput
 };
 
 
-export type MutationUpdateTaxCategoryArgs = {
-  input: UpdateTaxCategoryInput
+export type MutationUpdateRoleArgs = {
+  input: UpdateRoleInput
 };
 
 
-export type MutationCreateTaxRateArgs = {
-  input: CreateTaxRateInput
+export type MutationCreateTaxCategoryArgs = {
+  input: CreateTaxCategoryInput
 };
 
 
-export type MutationUpdateTaxRateArgs = {
-  input: UpdateTaxRateInput
+export type MutationUpdateTaxCategoryArgs = {
+  input: UpdateTaxCategoryInput
 };
 
 
@@ -2533,47 +2533,47 @@ export type Query = {
   administrator?: Maybe<Administrator>,
   assets: AssetList,
   asset?: Maybe<Asset>,
-  me?: Maybe<CurrentUser>,
-  channels: Array<Channel>,
-  channel?: Maybe<Channel>,
-  activeChannel: Channel,
   collections: CollectionList,
   collection?: Maybe<Collection>,
   collectionFilters: Array<ConfigurableOperation>,
-  countries: CountryList,
-  country?: Maybe<Country>,
-  customerGroups: Array<CustomerGroup>,
-  customerGroup?: Maybe<CustomerGroup>,
+  channels: Array<Channel>,
+  channel?: Maybe<Channel>,
+  activeChannel: Channel,
+  me?: Maybe<CurrentUser>,
   customers: CustomerList,
   customer?: Maybe<Customer>,
+  countries: CountryList,
+  country?: Maybe<Country>,
   facets: FacetList,
   facet?: Maybe<Facet>,
+  customerGroups: Array<CustomerGroup>,
+  customerGroup?: Maybe<CustomerGroup>,
   globalSettings: GlobalSettings,
   job?: Maybe<JobInfo>,
   jobs: Array<JobInfo>,
-  order?: Maybe<Order>,
-  orders: OrderList,
   paymentMethods: PaymentMethodList,
   paymentMethod?: Maybe<PaymentMethod>,
   productOptionGroups: Array<ProductOptionGroup>,
   productOptionGroup?: Maybe<ProductOptionGroup>,
-  search: SearchResponse,
+  order?: Maybe<Order>,
+  orders: OrderList,
   products: ProductList,
   /** Get a Product either by id or slug. If neither id nor slug is speicified, an error will result. */
   product?: Maybe<Product>,
   promotion?: Maybe<Promotion>,
   promotions: PromotionList,
   adjustmentOperations: AdjustmentOperations,
-  roles: RoleList,
-  role?: Maybe<Role>,
+  search: SearchResponse,
   shippingMethods: ShippingMethodList,
   shippingMethod?: Maybe<ShippingMethod>,
   shippingEligibilityCheckers: Array<ConfigurableOperation>,
   shippingCalculators: Array<ConfigurableOperation>,
-  taxCategories: Array<TaxCategory>,
-  taxCategory?: Maybe<TaxCategory>,
   taxRates: TaxRateList,
   taxRate?: Maybe<TaxRate>,
+  roles: RoleList,
+  role?: Maybe<Role>,
+  taxCategories: Array<TaxCategory>,
+  taxCategory?: Maybe<TaxCategory>,
   zones: Array<Zone>,
   zone?: Maybe<Zone>,
   networkStatus: NetworkStatus,
@@ -2602,11 +2602,6 @@ export type QueryAssetArgs = {
 };
 
 
-export type QueryChannelArgs = {
-  id: Scalars['ID']
-};
-
-
 export type QueryCollectionsArgs = {
   languageCode?: Maybe<LanguageCode>,
   options?: Maybe<CollectionListOptions>
@@ -2619,27 +2614,27 @@ export type QueryCollectionArgs = {
 };
 
 
-export type QueryCountriesArgs = {
-  options?: Maybe<CountryListOptions>
+export type QueryChannelArgs = {
+  id: Scalars['ID']
 };
 
 
-export type QueryCountryArgs = {
-  id: Scalars['ID']
+export type QueryCustomersArgs = {
+  options?: Maybe<CustomerListOptions>
 };
 
 
-export type QueryCustomerGroupArgs = {
+export type QueryCustomerArgs = {
   id: Scalars['ID']
 };
 
 
-export type QueryCustomersArgs = {
-  options?: Maybe<CustomerListOptions>
+export type QueryCountriesArgs = {
+  options?: Maybe<CountryListOptions>
 };
 
 
-export type QueryCustomerArgs = {
+export type QueryCountryArgs = {
   id: Scalars['ID']
 };
 
@@ -2656,6 +2651,11 @@ export type QueryFacetArgs = {
 };
 
 
+export type QueryCustomerGroupArgs = {
+  id: Scalars['ID']
+};
+
+
 export type QueryJobArgs = {
   jobId: Scalars['String']
 };
@@ -2666,16 +2666,6 @@ export type QueryJobsArgs = {
 };
 
 
-export type QueryOrderArgs = {
-  id: Scalars['ID']
-};
-
-
-export type QueryOrdersArgs = {
-  options?: Maybe<OrderListOptions>
-};
-
-
 export type QueryPaymentMethodsArgs = {
   options?: Maybe<PaymentMethodListOptions>
 };
@@ -2698,8 +2688,13 @@ export type QueryProductOptionGroupArgs = {
 };
 
 
-export type QuerySearchArgs = {
-  input: SearchInput
+export type QueryOrderArgs = {
+  id: Scalars['ID']
+};
+
+
+export type QueryOrdersArgs = {
+  options?: Maybe<OrderListOptions>
 };
 
 
@@ -2726,13 +2721,8 @@ export type QueryPromotionsArgs = {
 };
 
 
-export type QueryRolesArgs = {
-  options?: Maybe<RoleListOptions>
-};
-
-
-export type QueryRoleArgs = {
-  id: Scalars['ID']
+export type QuerySearchArgs = {
+  input: SearchInput
 };
 
 
@@ -2746,17 +2736,27 @@ export type QueryShippingMethodArgs = {
 };
 
 
-export type QueryTaxCategoryArgs = {
+export type QueryTaxRatesArgs = {
+  options?: Maybe<TaxRateListOptions>
+};
+
+
+export type QueryTaxRateArgs = {
   id: Scalars['ID']
 };
 
 
-export type QueryTaxRatesArgs = {
-  options?: Maybe<TaxRateListOptions>
+export type QueryRolesArgs = {
+  options?: Maybe<RoleListOptions>
 };
 
 
-export type QueryTaxRateArgs = {
+export type QueryRoleArgs = {
+  id: Scalars['ID']
+};
+
+
+export type QueryTaxCategoryArgs = {
   id: Scalars['ID']
 };
 
@@ -3776,6 +3776,13 @@ export type UpdateProductOptionMutationVariables = {
 
 export type UpdateProductOptionMutation = ({ __typename?: 'Mutation' } & { updateProductOption: ({ __typename?: 'ProductOption' } & Pick<ProductOption, 'id' | 'code' | 'name'>) });
 
+export type DeleteProductVariantMutationVariables = {
+  id: Scalars['ID']
+};
+
+
+export type DeleteProductVariantMutation = ({ __typename?: 'Mutation' } & { deleteProductVariant: ({ __typename?: 'DeletionResponse' } & Pick<DeletionResponse, 'result' | 'message'>) });
+
 export type ConfigurableOperationFragment = ({ __typename?: 'ConfigurableOperation' } & Pick<ConfigurableOperation, 'code' | 'description'> & { args: Array<({ __typename?: 'ConfigArg' } & Pick<ConfigArg, 'name' | 'type' | 'value'>)> });
 
 export type PromotionFragment = ({ __typename?: 'Promotion' } & Pick<Promotion, 'id' | 'createdAt' | 'updatedAt' | 'name' | 'enabled'> & { conditions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)>, actions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)> });
@@ -4623,6 +4630,12 @@ export namespace UpdateProductOption {
   export type UpdateProductOption = UpdateProductOptionMutation['updateProductOption'];
 }
 
+export namespace DeleteProductVariant {
+  export type Variables = DeleteProductVariantMutationVariables;
+  export type Mutation = DeleteProductVariantMutation;
+  export type DeleteProductVariant = DeleteProductVariantMutation['deleteProductVariant'];
+}
+
 export namespace ConfigurableOperation {
   export type Fragment = ConfigurableOperationFragment;
   export type Args = (NonNullable<ConfigurableOperationFragment['args'][0]>);

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

@@ -325,3 +325,12 @@ export const UPDATE_PRODUCT_OPTION = gql`
         }
     }
 `;
+
+export const DELETE_PRODUCT_VARIANT = gql`
+    mutation DeleteProductVariant($id: ID!) {
+        deleteProductVariant(id: $id) {
+            result
+            message
+        }
+    }
+`;

+ 11 - 0
admin-ui/src/app/data/providers/product-data.service.ts

@@ -10,6 +10,7 @@ import {
     CreateProductVariantInput,
     CreateProductVariants,
     DeleteProduct,
+    DeleteProductVariant,
     GetAssetList,
     GetProductList,
     GetProductOptionGroups,
@@ -33,6 +34,7 @@ import {
     CREATE_PRODUCT_OPTION_GROUP,
     CREATE_PRODUCT_VARIANTS,
     DELETE_PRODUCT,
+    DELETE_PRODUCT_VARIANT,
     GET_ASSET_LIST,
     GET_PRODUCT_LIST,
     GET_PRODUCT_OPTION_GROUPS,
@@ -158,6 +160,15 @@ export class ProductDataService {
         );
     }
 
+    deleteProductVariant(id: string) {
+        return this.baseDataService.mutate<DeleteProductVariant.Mutation, DeleteProductVariant.Variables>(
+            DELETE_PRODUCT_VARIANT,
+            {
+                id,
+            },
+        );
+    }
+
     createProductOptionGroups(productOptionGroup: CreateProductOptionGroupInput) {
         const input: CreateProductOptionGroup.Variables = {
             input: productOptionGroup,

+ 1 - 0
admin-ui/src/i18n-messages/en.json

@@ -33,6 +33,7 @@
     "confirm-delete-facet": "Delete facet?",
     "confirm-delete-facet-value": "Delete facet value?",
     "confirm-delete-product": "Delete product?",
+    "confirm-delete-product-variant": "Delete product variant?",
     "create-new-collection": "Create new collection",
     "create-new-facet": "Create new facet",
     "create-new-product": "New product",