@vendure/admin-ui 1.6.5 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/bundles/vendure-admin-ui-catalog.umd.js +196 -20
  2. package/bundles/vendure-admin-ui-catalog.umd.js.map +1 -1
  3. package/bundles/vendure-admin-ui-core.umd.js +263 -301
  4. package/bundles/vendure-admin-ui-core.umd.js.map +1 -1
  5. package/bundles/vendure-admin-ui-customer.umd.js +39 -18
  6. package/bundles/vendure-admin-ui-customer.umd.js.map +1 -1
  7. package/bundles/vendure-admin-ui-order.umd.js +141 -119
  8. package/bundles/vendure-admin-ui-order.umd.js.map +1 -1
  9. package/catalog/components/generate-product-variants/generate-product-variants.component.d.ts +3 -3
  10. package/catalog/components/option-value-input/option-value-input.component.d.ts +20 -8
  11. package/catalog/components/product-variants-editor/product-variants-editor.component.d.ts +10 -3
  12. package/catalog/vendure-admin-ui-catalog.metadata.json +1 -1
  13. package/core/common/generated-types.d.ts +89 -19
  14. package/core/common/utilities/configurable-operation-utils.d.ts +4 -2
  15. package/core/common/version.d.ts +1 -1
  16. package/core/data/definitions/order-definitions.d.ts +2 -0
  17. package/core/data/definitions/product-definitions.d.ts +1 -0
  18. package/core/data/providers/order-data.service.d.ts +1 -0
  19. package/core/data/providers/product-data.service.d.ts +1 -0
  20. package/core/shared/components/data-table/data-table.component.d.ts +5 -2
  21. package/core/vendure-admin-ui-core.metadata.json +1 -1
  22. package/customer/components/customer-group-list/customer-group-list.component.d.ts +6 -4
  23. package/customer/vendure-admin-ui-customer.metadata.json +1 -1
  24. package/esm2015/catalog/components/generate-product-variants/generate-product-variants.component.js +12 -5
  25. package/esm2015/catalog/components/option-value-input/option-value-input.component.js +62 -12
  26. package/esm2015/catalog/components/product-variants-editor/product-variants-editor.component.js +109 -11
  27. package/esm2015/core/common/generated-types.js +2 -1
  28. package/esm2015/core/common/introspection-result.js +191 -255
  29. package/esm2015/core/common/utilities/configurable-operation-utils.js +11 -8
  30. package/esm2015/core/common/version.js +2 -2
  31. package/esm2015/core/components/app-shell/app-shell.component.js +1 -1
  32. package/esm2015/core/components/main-nav/main-nav.component.js +1 -1
  33. package/esm2015/core/data/definitions/order-definitions.js +445 -431
  34. package/esm2015/core/data/definitions/product-definitions.js +9 -1
  35. package/esm2015/core/data/providers/order-data.service.js +7 -2
  36. package/esm2015/core/data/providers/product-data.service.js +5 -2
  37. package/esm2015/core/shared/components/data-table/data-table.component.js +9 -2
  38. package/esm2015/customer/components/customer-group-list/customer-group-list.component.js +25 -12
  39. package/esm2015/order/components/fulfill-order-dialog/fulfill-order-dialog.component.js +3 -2
  40. package/esm2015/order/components/fulfillment-detail/fulfillment-detail.component.js +9 -18
  41. package/esm2015/order/components/line-fulfillment/line-fulfillment.component.js +10 -21
  42. package/esm2015/order/components/order-custom-fields-card/order-custom-fields-card.component.js +30 -4
  43. package/esm2015/order/components/order-detail/order-detail.component.js +49 -20
  44. package/esm2015/order/components/order-list/order-list.component.js +22 -15
  45. package/esm2015/order/components/order-payment-card/order-payment-card.component.js +2 -2
  46. package/fesm2015/vendure-admin-ui-catalog.js +177 -22
  47. package/fesm2015/vendure-admin-ui-catalog.js.map +1 -1
  48. package/fesm2015/vendure-admin-ui-core.js +687 -710
  49. package/fesm2015/vendure-admin-ui-core.js.map +1 -1
  50. package/fesm2015/vendure-admin-ui-customer.js +23 -11
  51. package/fesm2015/vendure-admin-ui-customer.js.map +1 -1
  52. package/fesm2015/vendure-admin-ui-order.js +116 -75
  53. package/fesm2015/vendure-admin-ui-order.js.map +1 -1
  54. package/order/components/line-fulfillment/line-fulfillment.component.d.ts +2 -2
  55. package/order/components/modification-detail/modification-detail.component.d.ts +1 -1
  56. package/order/components/order-custom-fields-card/order-custom-fields-card.component.d.ts +4 -2
  57. package/order/components/order-list/order-list.component.d.ts +1 -0
  58. package/order/vendure-admin-ui-order.metadata.json +1 -1
  59. package/package.json +2 -2
  60. package/static/i18n-messages/cs.json +6 -2
  61. package/static/i18n-messages/de.json +6 -2
  62. package/static/i18n-messages/en.json +8 -3
  63. package/static/i18n-messages/es.json +6 -2
  64. package/static/i18n-messages/fr.json +6 -2
  65. package/static/i18n-messages/it.json +6 -2
  66. package/static/i18n-messages/pl.json +6 -2
  67. package/static/i18n-messages/pt_BR.json +6 -2
  68. package/static/i18n-messages/pt_PT.json +6 -2
  69. package/static/i18n-messages/ru.json +6 -2
  70. package/static/i18n-messages/uk.json +6 -2
  71. package/static/i18n-messages/zh_Hans.json +6 -2
  72. package/static/i18n-messages/zh_Hant.json +6 -2
  73. package/static/styles/_variables.scss +3 -0
  74. package/static/styles/global/_sass-overrides.scss +3 -0
  75. package/static/styles/global/_utilities.scss +1 -0
  76. package/static/styles/styles.scss +1 -0
  77. package/static/styles/ui-extension-theme.scss +1 -0
  78. package/static/theme.min.css +1 -1
@@ -2864,6 +2864,7 @@
2864
2864
  this.notificationService = notificationService;
2865
2865
  this.modalService = modalService;
2866
2866
  this.formValueChanged = false;
2867
+ this.optionsChanged = false;
2867
2868
  this.generatedVariants = [];
2868
2869
  }
2869
2870
  ProductVariantsEditorComponent.prototype.ngOnInit = function () {
@@ -2890,16 +2891,110 @@
2890
2891
  ? ngxTranslateExtractMarker.marker('catalog.default-variant')
2891
2892
  : variant.options.map(function (o) { return o.name; }).join(' ');
2892
2893
  };
2893
- ProductVariantsEditorComponent.prototype.addOption = function () {
2894
+ ProductVariantsEditorComponent.prototype.addOptionGroup = function () {
2894
2895
  this.optionGroups.push({
2895
2896
  isNew: true,
2897
+ locked: false,
2896
2898
  name: '',
2897
2899
  values: [],
2898
2900
  });
2901
+ this.optionsChanged = true;
2899
2902
  };
2900
- ProductVariantsEditorComponent.prototype.removeOption = function (optionGroup) {
2901
- this.optionGroups = this.optionGroups.filter(function (og) { return og !== optionGroup; });
2903
+ ProductVariantsEditorComponent.prototype.removeOptionGroup = function (optionGroup) {
2904
+ var _this = this;
2905
+ var id = optionGroup.id;
2906
+ if (optionGroup.isNew) {
2907
+ this.optionGroups = this.optionGroups.filter(function (og) { return og !== optionGroup; });
2908
+ this.generateVariants();
2909
+ this.optionsChanged = true;
2910
+ }
2911
+ else if (id) {
2912
+ this.modalService
2913
+ .dialog({
2914
+ title: ngxTranslateExtractMarker.marker('catalog.confirm-delete-product-option-group'),
2915
+ translationVars: { name: optionGroup.name },
2916
+ buttons: [
2917
+ { type: 'secondary', label: ngxTranslateExtractMarker.marker('common.cancel') },
2918
+ { type: 'danger', label: ngxTranslateExtractMarker.marker('common.delete'), returnValue: true },
2919
+ ],
2920
+ })
2921
+ .pipe(operators.switchMap(function (val) {
2922
+ if (val) {
2923
+ return _this.dataService.product.removeOptionGroupFromProduct({
2924
+ optionGroupId: id,
2925
+ productId: _this.product.id,
2926
+ });
2927
+ }
2928
+ else {
2929
+ return rxjs.EMPTY;
2930
+ }
2931
+ }))
2932
+ .subscribe(function (_g) {
2933
+ var removeOptionGroupFromProduct = _g.removeOptionGroupFromProduct;
2934
+ var _a;
2935
+ if (removeOptionGroupFromProduct.__typename === 'Product') {
2936
+ _this.notificationService.success(ngxTranslateExtractMarker.marker('common.notify-delete-success'), {
2937
+ entity: 'ProductOptionGroup',
2938
+ });
2939
+ _this.initOptionsAndVariants();
2940
+ _this.optionsChanged = true;
2941
+ }
2942
+ else if (removeOptionGroupFromProduct.__typename === 'ProductOptionInUseError') {
2943
+ _this.notificationService.error((_a = removeOptionGroupFromProduct.message) !== null && _a !== void 0 ? _a : '');
2944
+ }
2945
+ });
2946
+ }
2947
+ };
2948
+ ProductVariantsEditorComponent.prototype.addOption = function (groupId, optionName) {
2949
+ var _a;
2950
+ (_a = this.optionGroups.find(function (g) { return g.id === groupId; })) === null || _a === void 0 ? void 0 : _a.values.push({ name: optionName, locked: false });
2902
2951
  this.generateVariants();
2952
+ this.optionsChanged = true;
2953
+ };
2954
+ ProductVariantsEditorComponent.prototype.removeOption = function (groupId, _g) {
2955
+ var _this = this;
2956
+ var id = _g.id, name = _g.name;
2957
+ var optionGroup = this.optionGroups.find(function (g) { return g.id === groupId; });
2958
+ if (optionGroup) {
2959
+ if (!id) {
2960
+ optionGroup.values = optionGroup.values.filter(function (v) { return v.name !== name; });
2961
+ this.generateVariants();
2962
+ }
2963
+ else {
2964
+ this.modalService
2965
+ .dialog({
2966
+ title: ngxTranslateExtractMarker.marker('catalog.confirm-delete-product-option'),
2967
+ translationVars: { name: name },
2968
+ buttons: [
2969
+ { type: 'secondary', label: ngxTranslateExtractMarker.marker('common.cancel') },
2970
+ { type: 'danger', label: ngxTranslateExtractMarker.marker('common.delete'), returnValue: true },
2971
+ ],
2972
+ })
2973
+ .pipe(operators.switchMap(function (val) {
2974
+ if (val) {
2975
+ return _this.dataService.product.deleteProductOption(id);
2976
+ }
2977
+ else {
2978
+ return rxjs.EMPTY;
2979
+ }
2980
+ }))
2981
+ .subscribe(function (_g) {
2982
+ var deleteProductOption = _g.deleteProductOption;
2983
+ var _a;
2984
+ if (deleteProductOption.result === i2.DeletionResult.DELETED) {
2985
+ _this.notificationService.success(ngxTranslateExtractMarker.marker('common.notify-delete-success'), {
2986
+ entity: 'ProductOption',
2987
+ });
2988
+ optionGroup.values = optionGroup.values.filter(function (v) { return v.id !== id; });
2989
+ _this.generateVariants();
2990
+ _this.optionsChanged = true;
2991
+ }
2992
+ else {
2993
+ _this.notificationService.error((_a = deleteProductOption.message) !== null && _a !== void 0 ? _a : '');
2994
+ }
2995
+ });
2996
+ }
2997
+ }
2903
2998
  };
2904
2999
  ProductVariantsEditorComponent.prototype.generateVariants = function () {
2905
3000
  var _this = this;
@@ -2942,11 +3037,12 @@
2942
3037
  stock: 0,
2943
3038
  };
2944
3039
  };
2945
- ProductVariantsEditorComponent.prototype.deleteVariant = function (id) {
3040
+ ProductVariantsEditorComponent.prototype.deleteVariant = function (id, options) {
2946
3041
  var _this = this;
2947
3042
  this.modalService
2948
3043
  .dialog({
2949
3044
  title: ngxTranslateExtractMarker.marker('catalog.confirm-delete-product-variant'),
3045
+ translationVars: { name: options.map(function (o) { return o.name; }).join(' ') },
2950
3046
  buttons: [
2951
3047
  { type: 'secondary', label: ngxTranslateExtractMarker.marker('common.cancel') },
2952
3048
  { type: 'danger', label: ngxTranslateExtractMarker.marker('common.delete'), returnValue: true },
@@ -2982,13 +3078,15 @@
2982
3078
  count: variants.length,
2983
3079
  });
2984
3080
  _this.initOptionsAndVariants();
3081
+ _this.optionsChanged = false;
2985
3082
  },
2986
3083
  });
2987
3084
  };
2988
3085
  ProductVariantsEditorComponent.prototype.checkUniqueSkus = function () {
2989
3086
  var _this = this;
2990
3087
  var withDuplicateSkus = this.generatedVariants.filter(function (variant, index) {
2991
- return _this.generatedVariants.find(function (gv) { return gv.sku.trim() === variant.sku.trim() && gv !== variant; });
3088
+ return (variant.enabled &&
3089
+ _this.generatedVariants.find(function (gv) { return gv.sku.trim() === variant.sku.trim() && gv !== variant; }));
2992
3090
  });
2993
3091
  if (withDuplicateSkus.length) {
2994
3092
  return this.modalService
@@ -3072,7 +3170,7 @@
3072
3170
  return rxjs.forkJoin(groupsIds.map(function (id) { return _this.dataService.product
3073
3171
  .getProductOptionGroup(id)
3074
3172
  .mapSingle(function (data) { return data.productOptionGroup; })
3075
- .pipe(operators.filter(sharedUtils.notNullOrUndefined)); }));
3173
+ .pipe(operators.filter(sharedUtils.notNullOrUndefined)); })).pipe(operators.defaultIfEmpty([]));
3076
3174
  };
3077
3175
  ProductVariantsEditorComponent.prototype.createNewProductVariants = function (groups) {
3078
3176
  var options = groups
@@ -3125,15 +3223,20 @@
3125
3223
  })
3126
3224
  .subscribe(function (p) {
3127
3225
  _this.product = p;
3226
+ var allUsedOptionIds = p.variants.map(function (v) { return v.options.map(function (option) { return option.id; }); }).flat();
3227
+ var allUsedOptionGroupIds = p.variants
3228
+ .map(function (v) { return v.options.map(function (option) { return option.groupId; }); })
3229
+ .flat();
3128
3230
  _this.optionGroups = p.optionGroups.map(function (og) {
3129
3231
  return {
3130
3232
  id: og.id,
3131
3233
  isNew: false,
3132
3234
  name: og.name,
3235
+ locked: allUsedOptionGroupIds.includes(og.id),
3133
3236
  values: og.options.map(function (o) { return ({
3134
3237
  id: o.id,
3135
3238
  name: o.name,
3136
- locked: true,
3239
+ locked: allUsedOptionIds.includes(o.id),
3137
3240
  }); }),
3138
3241
  };
3139
3242
  });
@@ -3157,7 +3260,7 @@
3157
3260
  ProductVariantsEditorComponent.decorators = [
3158
3261
  { type: i0.Component, args: [{
3159
3262
  selector: 'vdr-product-variants-editor',
3160
- template: "<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"!formValueChanged || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div>\r\n <button *ngIf=\"group.isNew\" class=\"btn btn-icon btn-danger-outline mt5\" (click)=\"removeOption(group)\">\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button\r\n class=\"btn btn-primary-outline btn-sm\"\r\n (click)=\"addOption()\"\r\n>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.create' | translate }}</th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n *ngIf=\"!variant.existing\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n",
3263
+ template: "<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(!formValueChanged && !optionsChanged) || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [options]=\"group.values\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n (add)=\"addOption(group.id, $event.name)\"\r\n (remove)=\"removeOption(group.id, $event)\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div>\r\n <button\r\n [disabled]=\"group.locked\"\r\n class=\"btn btn-icon btn-danger-outline mt5\" (click)=\"removeOptionGroup(group)\">\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOptionGroup()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td class=\"left\">\r\n <clr-checkbox-wrapper *ngIf=\"!variant.existing\">\r\n <input\r\n type=\"checkbox\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n <label>{{ 'common.create' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <div class=\"flex center\">\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </div>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId, variant.options)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n",
3161
3264
  changeDetection: i0.ChangeDetectionStrategy.Default,
3162
3265
  styles: [".option-groups{display:flex}.option-groups:first-of-type{margin-top:24px}.values{flex:1;margin:0 6px}.variants-preview tr.disabled td{background-color:var(--color-component-bg-100);color:var(--color-grey-400)}\n"]
3163
3266
  },] }
@@ -3976,7 +4079,14 @@
3976
4079
  this.generateVariants();
3977
4080
  };
3978
4081
  GenerateProductVariantsComponent.prototype.addOption = function () {
4082
+ var _this = this;
3979
4083
  this.optionGroups.push({ name: '', values: [] });
4084
+ var index = this.optionGroups.length - 1;
4085
+ setTimeout(function () {
4086
+ var _a;
4087
+ var input = (_a = _this.groupNameInputs.get(index)) === null || _a === void 0 ? void 0 : _a.nativeElement;
4088
+ input === null || input === void 0 ? void 0 : input.focus();
4089
+ });
3980
4090
  };
3981
4091
  GenerateProductVariantsComponent.prototype.removeOption = function (name) {
3982
4092
  this.optionGroups = this.optionGroups.filter(function (g) { return g.name !== name; });
@@ -4028,7 +4138,7 @@
4028
4138
  GenerateProductVariantsComponent.decorators = [
4029
4139
  { type: i0.Component, args: [{
4030
4140
  selector: 'vdr-generate-product-variants',
4031
- template: "<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input\r\n placeholder=\"e.g. Size\"\r\n clrInput\r\n [(ngModel)]=\"group.name\"\r\n name=\"name\"\r\n required\r\n (keydown.enter)=\"handleEnter($event, optionValueInputComponent)\"\r\n />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div class=\"remove-group\">\r\n <button\r\n class=\"btn btn-icon btn-warning-outline\"\r\n [title]=\"'catalog.remove-option' | translate\"\r\n (click)=\"removeOption(group.name)\"\r\n >\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOption()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th *ngIf=\"1 < variants.length\">{{ 'common.create' | translate }}</th>\r\n <th *ngIf=\"1 < variants.length\">{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tr\r\n *ngFor=\"let variant of variants; trackBy: trackByFn\"\r\n [class.disabled]=\"!variantFormValues[variant.id].enabled\"\r\n >\r\n <td *ngIf=\"1 < variants.length\">\r\n <input\r\n type=\"checkbox\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].enabled\"\r\n clrCheckbox\r\n />\r\n </td>\r\n <td *ngIf=\"1 < variants.length\">\r\n {{ variant.values.join(' ') }}\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variantFormValues[variant.id].price\"\r\n (ngModelChange)=\"onFormChange()\"\r\n [currencyCode]=\"currencyCode\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variantFormValues[variant.id].stock\"\r\n (change)=\"onFormChange()\"\r\n min=\"0\"\r\n step=\"1\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n",
4141
+ template: "<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input\r\n #optionGroupName\r\n placeholder=\"e.g. Size\"\r\n clrInput\r\n [(ngModel)]=\"group.name\"\r\n name=\"name\"\r\n required\r\n (keydown.enter)=\"handleEnter($event, optionValueInputComponent)\"\r\n />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n (edit)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div class=\"remove-group\">\r\n <button\r\n class=\"btn btn-icon btn-warning-outline\"\r\n [title]=\"'catalog.remove-option' | translate\"\r\n (click)=\"removeOption(group.name)\"\r\n >\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOption()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th *ngIf=\"1 < variants.length\">{{ 'common.create' | translate }}</th>\r\n <th *ngIf=\"1 < variants.length\">{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tr\r\n *ngFor=\"let variant of variants; trackBy: trackByFn\"\r\n [class.disabled]=\"!variantFormValues[variant.id].enabled\"\r\n >\r\n <td *ngIf=\"1 < variants.length\">\r\n <input\r\n type=\"checkbox\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].enabled\"\r\n clrCheckbox\r\n />\r\n </td>\r\n <td *ngIf=\"1 < variants.length\">\r\n {{ variant.values.join(' ') }}\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variantFormValues[variant.id].price\"\r\n (ngModelChange)=\"onFormChange()\"\r\n [currencyCode]=\"currencyCode\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variantFormValues[variant.id].stock\"\r\n (change)=\"onFormChange()\"\r\n min=\"0\"\r\n step=\"1\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n",
4032
4142
  styles: [":host{display:block;margin-bottom:120px}.option-groups{display:flex}.values{flex:1;margin:0 6px}.remove-group{padding-top:18px}.variants-preview tr.disabled td{background-color:var(--color-component-bg-100);color:var(--color-grey-400)}\n"]
4033
4143
  },] }
4034
4144
  ];
@@ -4036,7 +4146,8 @@
4036
4146
  { type: i2.DataService }
4037
4147
  ]; };
4038
4148
  GenerateProductVariantsComponent.propDecorators = {
4039
- variantsChange: [{ type: i0.Output }]
4149
+ variantsChange: [{ type: i0.Output }],
4150
+ groupNameInputs: [{ type: i0.ViewChildren, args: ['optionGroupName', { read: i0.ElementRef },] }]
4040
4151
  };
4041
4152
 
4042
4153
  var OPTION_VALUE_INPUT_VALUE_ACCESSOR = {
@@ -4048,11 +4159,23 @@
4048
4159
  function OptionValueInputComponent(changeDetector) {
4049
4160
  this.changeDetector = changeDetector;
4050
4161
  this.groupName = '';
4162
+ this.add = new i0.EventEmitter();
4163
+ this.remove = new i0.EventEmitter();
4164
+ this.edit = new i0.EventEmitter();
4051
4165
  this.disabled = false;
4052
4166
  this.input = '';
4053
4167
  this.isFocussed = false;
4054
4168
  this.lastSelected = false;
4169
+ this.editingIndex = -1;
4055
4170
  }
4171
+ Object.defineProperty(OptionValueInputComponent.prototype, "optionValues", {
4172
+ get: function () {
4173
+ var _a, _b;
4174
+ return (_b = (_a = this.formValue) !== null && _a !== void 0 ? _a : this.options) !== null && _b !== void 0 ? _b : [];
4175
+ },
4176
+ enumerable: false,
4177
+ configurable: true
4178
+ });
4056
4179
  OptionValueInputComponent.prototype.registerOnChange = function (fn) {
4057
4180
  this.onChangeFn = fn;
4058
4181
  };
@@ -4064,15 +4187,42 @@
4064
4187
  this.changeDetector.markForCheck();
4065
4188
  };
4066
4189
  OptionValueInputComponent.prototype.writeValue = function (obj) {
4067
- this.options = obj || [];
4190
+ this.formValue = obj || [];
4068
4191
  };
4069
4192
  OptionValueInputComponent.prototype.focus = function () {
4070
4193
  this.textArea.nativeElement.focus();
4071
4194
  };
4195
+ OptionValueInputComponent.prototype.editName = function (index, event) {
4196
+ var _a;
4197
+ var optionValue = this.optionValues[index];
4198
+ if (!optionValue.locked && !optionValue.id) {
4199
+ event.cancelBubble = true;
4200
+ this.editingIndex = index;
4201
+ var input_1 = (_a = this.nameInputs.get(index)) === null || _a === void 0 ? void 0 : _a.nativeElement;
4202
+ setTimeout(function () { return input_1 === null || input_1 === void 0 ? void 0 : input_1.focus(); });
4203
+ }
4204
+ };
4205
+ OptionValueInputComponent.prototype.updateOption = function (index, event) {
4206
+ var optionValue = this.optionValues[index];
4207
+ var newName = event.target.value;
4208
+ if (optionValue) {
4209
+ if (newName) {
4210
+ optionValue.name = newName;
4211
+ this.edit.emit({ index: index, option: optionValue });
4212
+ }
4213
+ this.editingIndex = -1;
4214
+ }
4215
+ };
4072
4216
  OptionValueInputComponent.prototype.removeOption = function (option) {
4217
+ var _a;
4073
4218
  if (!option.locked) {
4074
- this.options = this.options.filter(function (o) { return o.name !== option.name; });
4075
- this.onChangeFn(this.options);
4219
+ if (this.formValue) {
4220
+ this.formValue = (_a = this.formValue) === null || _a === void 0 ? void 0 : _a.filter(function (o) { return o.name !== option.name; });
4221
+ this.onChangeFn(this.formValue);
4222
+ }
4223
+ else {
4224
+ this.remove.emit(option);
4225
+ }
4076
4226
  }
4077
4227
  };
4078
4228
  OptionValueInputComponent.prototype.handleKey = function (event) {
@@ -4100,9 +4250,28 @@
4100
4250
  this.addOptionValue();
4101
4251
  };
4102
4252
  OptionValueInputComponent.prototype.addOptionValue = function () {
4103
- this.options = unique.unique(__spreadArray(__spreadArray([], __read(this.options)), __read(this.parseInputIntoOptions(this.input))));
4253
+ var e_1, _c;
4254
+ var options = this.parseInputIntoOptions(this.input);
4255
+ if (!this.formValue && this.options) {
4256
+ try {
4257
+ for (var options_1 = __values(options), options_1_1 = options_1.next(); !options_1_1.done; options_1_1 = options_1.next()) {
4258
+ var option = options_1_1.value;
4259
+ this.add.emit(option);
4260
+ }
4261
+ }
4262
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
4263
+ finally {
4264
+ try {
4265
+ if (options_1_1 && !options_1_1.done && (_c = options_1.return)) _c.call(options_1);
4266
+ }
4267
+ finally { if (e_1) throw e_1.error; }
4268
+ }
4269
+ }
4270
+ else {
4271
+ this.formValue = unique.unique(__spreadArray(__spreadArray([], __read(this.formValue)), __read(options)));
4272
+ this.onChangeFn(this.formValue);
4273
+ }
4104
4274
  this.input = '';
4105
- this.onChangeFn(this.options);
4106
4275
  };
4107
4276
  OptionValueInputComponent.prototype.parseInputIntoOptions = function (input) {
4108
4277
  return input
@@ -4112,8 +4281,9 @@
4112
4281
  .map(function (s) { return ({ name: s, locked: false }); });
4113
4282
  };
4114
4283
  OptionValueInputComponent.prototype.removeLastOption = function () {
4115
- if (!this.options[this.options.length - 1].locked) {
4116
- this.options = this.options.slice(0, this.options.length - 1);
4284
+ if (this.optionValues.length) {
4285
+ var option = this.optionValues[this.optionValues.length - 1];
4286
+ this.removeOption(option);
4117
4287
  }
4118
4288
  };
4119
4289
  return OptionValueInputComponent;
@@ -4121,10 +4291,10 @@
4121
4291
  OptionValueInputComponent.decorators = [
4122
4292
  { type: i0.Component, args: [{
4123
4293
  selector: 'vdr-option-value-input',
4124
- template: "<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 < options.length\">\r\n <vdr-chip\r\n *ngFor=\"let option of options; last as isLast\"\r\n [icon]=\"option.locked ? 'lock' : 'times'\"\r\n [class.selected]=\"isLast && lastSelected\"\r\n [class.locked]=\"option.locked\"\r\n [colorFrom]=\"groupName\"\r\n (iconClick)=\"removeOption(option)\"\r\n >\r\n {{ option.name }}\r\n </vdr-chip>\r\n </div>\r\n <textarea\r\n #textArea\r\n (keyup)=\"handleKey($event)\"\r\n (focus)=\"isFocussed = true\"\r\n (blur)=\"handleBlur()\"\r\n [(ngModel)]=\"input\"\r\n [disabled]=\"disabled\"\r\n ></textarea>\r\n</div>\r\n",
4294
+ template: "<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 < optionValues.length\">\r\n <vdr-chip\r\n *ngFor=\"let option of optionValues; last as isLast; index as i\"\r\n [icon]=\"option.locked ? 'lock' : 'times'\"\r\n [class.selected]=\"isLast && lastSelected\"\r\n [class.locked]=\"option.locked\"\r\n [colorFrom]=\"groupName\"\r\n (iconClick)=\"removeOption(option)\"\r\n >\r\n <span [hidden]=\"editingIndex !== i\">\r\n <input\r\n #editNameInput\r\n type=\"text\"\r\n [ngModel]=\"option.name\"\r\n (blur)=\"updateOption(i, $event)\"\r\n (click)=\"$event.cancelBubble = true\"\r\n />\r\n </span>\r\n <span\r\n class=\"option-name\"\r\n [class.editable]=\"!option.locked && !option.id\"\r\n (click)=\"editName(i, $event)\" [hidden]=\"editingIndex === i\">{{ option.name }}</span>\r\n </vdr-chip>\r\n </div>\r\n <textarea\r\n #textArea\r\n (keyup)=\"handleKey($event)\"\r\n (focus)=\"isFocussed = true\"\r\n (blur)=\"handleBlur()\"\r\n [(ngModel)]=\"input\"\r\n [disabled]=\"disabled\"\r\n ></textarea>\r\n</div>\r\n",
4125
4295
  changeDetection: i0.ChangeDetectionStrategy.Default,
4126
4296
  providers: [OPTION_VALUE_INPUT_VALUE_ACCESSOR],
4127
- styles: [".input-wrapper{background-color:#fff;border-radius:3px!important;border:1px solid var(--color-grey-300)!important;cursor:text}.input-wrapper.focus{border-color:var(--color-primary-500)!important;box-shadow:0 0 1px 1px var(--color-primary-100)}.input-wrapper .chips{padding:5px}.input-wrapper textarea{border:none;width:100%;height:24px;margin-top:3px;padding:0 6px}.input-wrapper textarea:focus{outline:none}.input-wrapper textarea:disabled{background-color:var(--color-component-bg-100)}vdr-chip ::ng-deep .wrapper{margin:0 3px}vdr-chip.locked{opacity:.8}vdr-chip.selected ::ng-deep .wrapper{border-color:var(--color-warning-500)!important;box-shadow:0 0 1px 1px var(--color-warning-400);opacity:.6}\n"]
4297
+ styles: [".input-wrapper{background-color:#fff;border-radius:3px!important;border:1px solid var(--color-grey-300)!important;cursor:text}.input-wrapper.focus{border-color:var(--color-primary-500)!important;box-shadow:0 0 1px 1px var(--color-primary-100)}.input-wrapper .chips{padding:5px}.input-wrapper textarea{border:none;width:100%;height:24px;margin-top:3px;padding:0 6px}.input-wrapper textarea:focus{outline:none}.input-wrapper textarea:disabled{background-color:var(--color-component-bg-100)}vdr-chip ::ng-deep .wrapper{margin:0 3px}vdr-chip.locked{opacity:.8}vdr-chip.selected ::ng-deep .wrapper{border-color:var(--color-warning-500)!important;box-shadow:0 0 1px 1px var(--color-warning-400);opacity:.6}vdr-chip .option-name.editable:hover{outline:1px solid var(--color-component-bg-300);outline-offset:1px;border-radius:1px}vdr-chip input{padding:0!important;margin-top:-2px;margin-bottom:-2px}\n"]
4128
4298
  },] }
4129
4299
  ];
4130
4300
  OptionValueInputComponent.ctorParameters = function () { return [
@@ -4132,7 +4302,13 @@
4132
4302
  ]; };
4133
4303
  OptionValueInputComponent.propDecorators = {
4134
4304
  groupName: [{ type: i0.Input }],
4135
- textArea: [{ type: i0.ViewChild, args: ['textArea', { static: true },] }]
4305
+ textArea: [{ type: i0.ViewChild, args: ['textArea', { static: true },] }],
4306
+ nameInputs: [{ type: i0.ViewChildren, args: ['editNameInput', { read: i0.ElementRef },] }],
4307
+ options: [{ type: i0.Input }],
4308
+ add: [{ type: i0.Output }],
4309
+ remove: [{ type: i0.Output }],
4310
+ edit: [{ type: i0.Output }],
4311
+ disabled: [{ type: i0.Input }]
4136
4312
  };
4137
4313
 
4138
4314
  var UpdateProductOptionDialogComponent = /** @class */ (function () {