@vendure/admin-ui 1.6.3 → 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.
- package/bundles/vendure-admin-ui-catalog.umd.js +196 -20
- package/bundles/vendure-admin-ui-catalog.umd.js.map +1 -1
- package/bundles/vendure-admin-ui-core.umd.js +309 -327
- package/bundles/vendure-admin-ui-core.umd.js.map +1 -1
- package/bundles/vendure-admin-ui-customer.umd.js +39 -18
- package/bundles/vendure-admin-ui-customer.umd.js.map +1 -1
- package/bundles/vendure-admin-ui-order.umd.js +179 -137
- package/bundles/vendure-admin-ui-order.umd.js.map +1 -1
- package/catalog/components/generate-product-variants/generate-product-variants.component.d.ts +3 -3
- package/catalog/components/option-value-input/option-value-input.component.d.ts +20 -8
- package/catalog/components/product-variants-editor/product-variants-editor.component.d.ts +10 -3
- package/catalog/vendure-admin-ui-catalog.metadata.json +1 -1
- package/core/common/generated-types.d.ts +91 -19
- package/core/common/utilities/configurable-operation-utils.d.ts +4 -2
- package/core/common/version.d.ts +1 -1
- package/core/data/definitions/order-definitions.d.ts +2 -0
- package/core/data/definitions/product-definitions.d.ts +1 -0
- package/core/data/providers/order-data.service.d.ts +1 -0
- package/core/data/providers/product-data.service.d.ts +1 -0
- package/core/shared/components/custom-field-control/custom-field-control.component.d.ts +6 -2
- package/core/shared/components/data-table/data-table.component.d.ts +5 -2
- package/core/shared/components/facet-value-selector/facet-value-selector.component.d.ts +2 -1
- package/core/shared/dynamic-form-inputs/facet-value-form-input/facet-value-form-input.component.d.ts +2 -0
- package/core/shared/dynamic-form-inputs/register-dynamic-input-components.d.ts +2 -1
- package/core/shared/dynamic-form-inputs/select-form-input/select-form-input.component.d.ts +10 -2
- package/core/shared/pipes/custom-field-label.pipe.d.ts +4 -10
- package/core/vendure-admin-ui-core.metadata.json +1 -1
- package/customer/components/customer-group-list/customer-group-list.component.d.ts +6 -4
- package/customer/vendure-admin-ui-customer.metadata.json +1 -1
- package/esm2015/catalog/components/generate-product-variants/generate-product-variants.component.js +12 -5
- package/esm2015/catalog/components/option-value-input/option-value-input.component.js +62 -12
- package/esm2015/catalog/components/product-variants-editor/product-variants-editor.component.js +109 -11
- package/esm2015/core/common/generated-types.js +2 -1
- package/esm2015/core/common/introspection-result.js +191 -255
- package/esm2015/core/common/utilities/configurable-operation-utils.js +13 -10
- package/esm2015/core/common/version.js +2 -2
- package/esm2015/core/components/app-shell/app-shell.component.js +1 -1
- package/esm2015/core/components/main-nav/main-nav.component.js +1 -1
- package/esm2015/core/data/definitions/order-definitions.js +445 -431
- package/esm2015/core/data/definitions/product-definitions.js +9 -1
- package/esm2015/core/data/providers/order-data.service.js +7 -2
- package/esm2015/core/data/providers/product-data.service.js +5 -2
- package/esm2015/core/shared/components/custom-field-control/custom-field-control.component.js +9 -3
- package/esm2015/core/shared/components/data-table/data-table.component.js +9 -2
- package/esm2015/core/shared/components/facet-value-selector/facet-value-selector.component.js +5 -2
- package/esm2015/core/shared/dynamic-form-inputs/facet-value-form-input/facet-value-form-input.component.js +11 -2
- package/esm2015/core/shared/dynamic-form-inputs/select-form-input/select-form-input.component.js +15 -2
- package/esm2015/core/shared/pipes/custom-field-label.pipe.js +4 -19
- package/esm2015/customer/components/customer-group-list/customer-group-list.component.js +25 -12
- package/esm2015/order/components/fulfill-order-dialog/fulfill-order-dialog.component.js +3 -2
- package/esm2015/order/components/fulfillment-detail/fulfillment-detail.component.js +9 -18
- package/esm2015/order/components/line-fulfillment/line-fulfillment.component.js +10 -21
- package/esm2015/order/components/order-custom-fields-card/order-custom-fields-card.component.js +30 -4
- package/esm2015/order/components/order-detail/order-detail.component.js +79 -38
- package/esm2015/order/components/order-list/order-list.component.js +22 -15
- package/esm2015/order/components/order-payment-card/order-payment-card.component.js +2 -2
- package/esm2015/order/components/order-table/order-table.component.js +10 -2
- package/fesm2015/vendure-admin-ui-catalog.js +177 -22
- package/fesm2015/vendure-admin-ui-catalog.js.map +1 -1
- package/fesm2015/vendure-admin-ui-core.js +725 -733
- package/fesm2015/vendure-admin-ui-core.js.map +1 -1
- package/fesm2015/vendure-admin-ui-customer.js +23 -11
- package/fesm2015/vendure-admin-ui-customer.js.map +1 -1
- package/fesm2015/vendure-admin-ui-order.js +155 -94
- package/fesm2015/vendure-admin-ui-order.js.map +1 -1
- package/order/components/line-fulfillment/line-fulfillment.component.d.ts +2 -2
- package/order/components/modification-detail/modification-detail.component.d.ts +1 -1
- package/order/components/order-custom-fields-card/order-custom-fields-card.component.d.ts +4 -2
- package/order/components/order-list/order-list.component.d.ts +1 -0
- package/order/components/order-table/order-table.component.d.ts +1 -0
- package/order/vendure-admin-ui-order.metadata.json +1 -1
- package/package.json +2 -2
- package/static/i18n-messages/cs.json +6 -2
- package/static/i18n-messages/de.json +6 -2
- package/static/i18n-messages/en.json +8 -3
- package/static/i18n-messages/es.json +6 -2
- package/static/i18n-messages/fr.json +6 -2
- package/static/i18n-messages/it.json +6 -2
- package/static/i18n-messages/pl.json +6 -2
- package/static/i18n-messages/pt_BR.json +6 -2
- package/static/i18n-messages/pt_PT.json +6 -2
- package/static/i18n-messages/ru.json +6 -2
- package/static/i18n-messages/uk.json +6 -2
- package/static/i18n-messages/zh_Hans.json +6 -2
- package/static/i18n-messages/zh_Hant.json +6 -2
- package/static/styles/_variables.scss +3 -0
- package/static/styles/global/_sass-overrides.scss +3 -0
- package/static/styles/global/_utilities.scss +1 -0
- package/static/styles/styles.scss +1 -0
- package/static/styles/ui-extension-theme.scss +1 -0
- package/static/theme.min.css +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, Injectable, EventEmitter, Input, HostBinding, Output, ContentChild, TemplateRef, SkipSelf, Optional, forwardRef, NgModule } from '@angular/core';
|
|
2
|
+
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, Injectable, EventEmitter, Input, HostBinding, Output, ContentChild, TemplateRef, SkipSelf, Optional, ViewChildren, ElementRef, forwardRef, NgModule } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/router';
|
|
4
4
|
import { Router, ActivatedRoute, RouterModule } from '@angular/router';
|
|
5
5
|
import * as i2 from '@vendure/admin-ui/core';
|
|
6
6
|
import { BaseDetailComponent, ServerConfigService, NotificationService, DataService, BaseListComponent, SortOrder, LogicalOperator, DeletionResult, ModalService, Permission, unicodePatternValidator, findTranslation, getConfigArgValue, createUpdatedTranslatable, encodeConfigArgValue, LocalStorageService, FacetValueSelectorComponent, flattenFacetValues, JobState, JobQueueService, getDefaultUiLanguage, BaseEntityResolver, AssetType, createResolveData, CanDeactivateDetailGuard, detailBreadcrumb, AssetPickerDialogComponent, AssetPreviewDialogComponent, GlobalFlag, SharedModule } from '@vendure/admin-ui/core';
|
|
7
7
|
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
|
|
8
|
-
import { map, debounceTime, takeUntil, finalize, switchMap, filter, take, mergeMap, shareReplay, distinctUntilChanged, tap, mapTo, startWith, skipUntil, skip, withLatestFrom, delay, catchError } from 'rxjs/operators';
|
|
8
|
+
import { map, debounceTime, takeUntil, finalize, switchMap, filter, take, mergeMap, shareReplay, distinctUntilChanged, tap, mapTo, startWith, skipUntil, skip, withLatestFrom, delay, defaultIfEmpty, catchError } from 'rxjs/operators';
|
|
9
9
|
import { FormGroup, FormControl, FormBuilder, Validators, FormArray, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
10
10
|
import { BehaviorSubject, combineLatest, EMPTY, Subject, merge, of, forkJoin, throwError, from } from 'rxjs';
|
|
11
11
|
import { normalizeString } from '@vendure/common/lib/normalize-string';
|
|
@@ -2184,6 +2184,7 @@ class ProductVariantsEditorComponent {
|
|
|
2184
2184
|
this.notificationService = notificationService;
|
|
2185
2185
|
this.modalService = modalService;
|
|
2186
2186
|
this.formValueChanged = false;
|
|
2187
|
+
this.optionsChanged = false;
|
|
2187
2188
|
this.generatedVariants = [];
|
|
2188
2189
|
}
|
|
2189
2190
|
ngOnInit() {
|
|
@@ -2209,16 +2210,105 @@ class ProductVariantsEditorComponent {
|
|
|
2209
2210
|
? marker('catalog.default-variant')
|
|
2210
2211
|
: variant.options.map(o => o.name).join(' ');
|
|
2211
2212
|
}
|
|
2212
|
-
|
|
2213
|
+
addOptionGroup() {
|
|
2213
2214
|
this.optionGroups.push({
|
|
2214
2215
|
isNew: true,
|
|
2216
|
+
locked: false,
|
|
2215
2217
|
name: '',
|
|
2216
2218
|
values: [],
|
|
2217
2219
|
});
|
|
2220
|
+
this.optionsChanged = true;
|
|
2218
2221
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2222
|
+
removeOptionGroup(optionGroup) {
|
|
2223
|
+
const id = optionGroup.id;
|
|
2224
|
+
if (optionGroup.isNew) {
|
|
2225
|
+
this.optionGroups = this.optionGroups.filter(og => og !== optionGroup);
|
|
2226
|
+
this.generateVariants();
|
|
2227
|
+
this.optionsChanged = true;
|
|
2228
|
+
}
|
|
2229
|
+
else if (id) {
|
|
2230
|
+
this.modalService
|
|
2231
|
+
.dialog({
|
|
2232
|
+
title: marker('catalog.confirm-delete-product-option-group'),
|
|
2233
|
+
translationVars: { name: optionGroup.name },
|
|
2234
|
+
buttons: [
|
|
2235
|
+
{ type: 'secondary', label: marker('common.cancel') },
|
|
2236
|
+
{ type: 'danger', label: marker('common.delete'), returnValue: true },
|
|
2237
|
+
],
|
|
2238
|
+
})
|
|
2239
|
+
.pipe(switchMap(val => {
|
|
2240
|
+
if (val) {
|
|
2241
|
+
return this.dataService.product.removeOptionGroupFromProduct({
|
|
2242
|
+
optionGroupId: id,
|
|
2243
|
+
productId: this.product.id,
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
else {
|
|
2247
|
+
return EMPTY;
|
|
2248
|
+
}
|
|
2249
|
+
}))
|
|
2250
|
+
.subscribe(({ removeOptionGroupFromProduct }) => {
|
|
2251
|
+
var _a;
|
|
2252
|
+
if (removeOptionGroupFromProduct.__typename === 'Product') {
|
|
2253
|
+
this.notificationService.success(marker('common.notify-delete-success'), {
|
|
2254
|
+
entity: 'ProductOptionGroup',
|
|
2255
|
+
});
|
|
2256
|
+
this.initOptionsAndVariants();
|
|
2257
|
+
this.optionsChanged = true;
|
|
2258
|
+
}
|
|
2259
|
+
else if (removeOptionGroupFromProduct.__typename === 'ProductOptionInUseError') {
|
|
2260
|
+
this.notificationService.error((_a = removeOptionGroupFromProduct.message) !== null && _a !== void 0 ? _a : '');
|
|
2261
|
+
}
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
addOption(groupId, optionName) {
|
|
2266
|
+
var _a;
|
|
2267
|
+
(_a = this.optionGroups.find(g => g.id === groupId)) === null || _a === void 0 ? void 0 : _a.values.push({ name: optionName, locked: false });
|
|
2221
2268
|
this.generateVariants();
|
|
2269
|
+
this.optionsChanged = true;
|
|
2270
|
+
}
|
|
2271
|
+
removeOption(groupId, { id, name }) {
|
|
2272
|
+
const optionGroup = this.optionGroups.find(g => g.id === groupId);
|
|
2273
|
+
if (optionGroup) {
|
|
2274
|
+
if (!id) {
|
|
2275
|
+
optionGroup.values = optionGroup.values.filter(v => v.name !== name);
|
|
2276
|
+
this.generateVariants();
|
|
2277
|
+
}
|
|
2278
|
+
else {
|
|
2279
|
+
this.modalService
|
|
2280
|
+
.dialog({
|
|
2281
|
+
title: marker('catalog.confirm-delete-product-option'),
|
|
2282
|
+
translationVars: { name },
|
|
2283
|
+
buttons: [
|
|
2284
|
+
{ type: 'secondary', label: marker('common.cancel') },
|
|
2285
|
+
{ type: 'danger', label: marker('common.delete'), returnValue: true },
|
|
2286
|
+
],
|
|
2287
|
+
})
|
|
2288
|
+
.pipe(switchMap(val => {
|
|
2289
|
+
if (val) {
|
|
2290
|
+
return this.dataService.product.deleteProductOption(id);
|
|
2291
|
+
}
|
|
2292
|
+
else {
|
|
2293
|
+
return EMPTY;
|
|
2294
|
+
}
|
|
2295
|
+
}))
|
|
2296
|
+
.subscribe(({ deleteProductOption }) => {
|
|
2297
|
+
var _a;
|
|
2298
|
+
if (deleteProductOption.result === DeletionResult.DELETED) {
|
|
2299
|
+
this.notificationService.success(marker('common.notify-delete-success'), {
|
|
2300
|
+
entity: 'ProductOption',
|
|
2301
|
+
});
|
|
2302
|
+
optionGroup.values = optionGroup.values.filter(v => v.id !== id);
|
|
2303
|
+
this.generateVariants();
|
|
2304
|
+
this.optionsChanged = true;
|
|
2305
|
+
}
|
|
2306
|
+
else {
|
|
2307
|
+
this.notificationService.error((_a = deleteProductOption.message) !== null && _a !== void 0 ? _a : '');
|
|
2308
|
+
}
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2222
2312
|
}
|
|
2223
2313
|
generateVariants() {
|
|
2224
2314
|
const groups = this.optionGroups.map(g => g.values);
|
|
@@ -2260,10 +2350,11 @@ class ProductVariantsEditorComponent {
|
|
|
2260
2350
|
stock: 0,
|
|
2261
2351
|
};
|
|
2262
2352
|
}
|
|
2263
|
-
deleteVariant(id) {
|
|
2353
|
+
deleteVariant(id, options) {
|
|
2264
2354
|
this.modalService
|
|
2265
2355
|
.dialog({
|
|
2266
2356
|
title: marker('catalog.confirm-delete-product-variant'),
|
|
2357
|
+
translationVars: { name: options.map(o => o.name).join(' ') },
|
|
2267
2358
|
buttons: [
|
|
2268
2359
|
{ type: 'secondary', label: marker('common.cancel') },
|
|
2269
2360
|
{ type: 'danger', label: marker('common.delete'), returnValue: true },
|
|
@@ -2298,12 +2389,14 @@ class ProductVariantsEditorComponent {
|
|
|
2298
2389
|
count: variants.length,
|
|
2299
2390
|
});
|
|
2300
2391
|
this.initOptionsAndVariants();
|
|
2392
|
+
this.optionsChanged = false;
|
|
2301
2393
|
},
|
|
2302
2394
|
});
|
|
2303
2395
|
}
|
|
2304
2396
|
checkUniqueSkus() {
|
|
2305
2397
|
const withDuplicateSkus = this.generatedVariants.filter((variant, index) => {
|
|
2306
|
-
return
|
|
2398
|
+
return (variant.enabled &&
|
|
2399
|
+
this.generatedVariants.find(gv => gv.sku.trim() === variant.sku.trim() && gv !== variant));
|
|
2307
2400
|
});
|
|
2308
2401
|
if (withDuplicateSkus.length) {
|
|
2309
2402
|
return this.modalService
|
|
@@ -2386,7 +2479,7 @@ class ProductVariantsEditorComponent {
|
|
|
2386
2479
|
return forkJoin(groupsIds.map(id => this.dataService.product
|
|
2387
2480
|
.getProductOptionGroup(id)
|
|
2388
2481
|
.mapSingle(data => data.productOptionGroup)
|
|
2389
|
-
.pipe(filter(notNullOrUndefined))));
|
|
2482
|
+
.pipe(filter(notNullOrUndefined)))).pipe(defaultIfEmpty([]));
|
|
2390
2483
|
}
|
|
2391
2484
|
createNewProductVariants(groups) {
|
|
2392
2485
|
const options = groups
|
|
@@ -2434,15 +2527,20 @@ class ProductVariantsEditorComponent {
|
|
|
2434
2527
|
.mapSingle(({ product }) => product)
|
|
2435
2528
|
.subscribe(p => {
|
|
2436
2529
|
this.product = p;
|
|
2530
|
+
const allUsedOptionIds = p.variants.map(v => v.options.map(option => option.id)).flat();
|
|
2531
|
+
const allUsedOptionGroupIds = p.variants
|
|
2532
|
+
.map(v => v.options.map(option => option.groupId))
|
|
2533
|
+
.flat();
|
|
2437
2534
|
this.optionGroups = p.optionGroups.map(og => {
|
|
2438
2535
|
return {
|
|
2439
2536
|
id: og.id,
|
|
2440
2537
|
isNew: false,
|
|
2441
2538
|
name: og.name,
|
|
2539
|
+
locked: allUsedOptionGroupIds.includes(og.id),
|
|
2442
2540
|
values: og.options.map(o => ({
|
|
2443
2541
|
id: o.id,
|
|
2444
2542
|
name: o.name,
|
|
2445
|
-
locked:
|
|
2543
|
+
locked: allUsedOptionIds.includes(o.id),
|
|
2446
2544
|
})),
|
|
2447
2545
|
};
|
|
2448
2546
|
});
|
|
@@ -2465,7 +2563,7 @@ class ProductVariantsEditorComponent {
|
|
|
2465
2563
|
ProductVariantsEditorComponent.decorators = [
|
|
2466
2564
|
{ type: Component, args: [{
|
|
2467
2565
|
selector: 'vdr-product-variants-editor',
|
|
2468
|
-
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 [
|
|
2566
|
+
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",
|
|
2469
2567
|
changeDetection: ChangeDetectionStrategy.Default,
|
|
2470
2568
|
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"]
|
|
2471
2569
|
},] }
|
|
@@ -3240,6 +3338,12 @@ class GenerateProductVariantsComponent {
|
|
|
3240
3338
|
}
|
|
3241
3339
|
addOption() {
|
|
3242
3340
|
this.optionGroups.push({ name: '', values: [] });
|
|
3341
|
+
const index = this.optionGroups.length - 1;
|
|
3342
|
+
setTimeout(() => {
|
|
3343
|
+
var _a;
|
|
3344
|
+
const input = (_a = this.groupNameInputs.get(index)) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
3345
|
+
input === null || input === void 0 ? void 0 : input.focus();
|
|
3346
|
+
});
|
|
3243
3347
|
}
|
|
3244
3348
|
removeOption(name) {
|
|
3245
3349
|
this.optionGroups = this.optionGroups.filter(g => g.name !== name);
|
|
@@ -3288,7 +3392,7 @@ class GenerateProductVariantsComponent {
|
|
|
3288
3392
|
GenerateProductVariantsComponent.decorators = [
|
|
3289
3393
|
{ type: Component, args: [{
|
|
3290
3394
|
selector: 'vdr-generate-product-variants',
|
|
3291
|
-
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",
|
|
3395
|
+
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",
|
|
3292
3396
|
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"]
|
|
3293
3397
|
},] }
|
|
3294
3398
|
];
|
|
@@ -3296,7 +3400,8 @@ GenerateProductVariantsComponent.ctorParameters = () => [
|
|
|
3296
3400
|
{ type: DataService }
|
|
3297
3401
|
];
|
|
3298
3402
|
GenerateProductVariantsComponent.propDecorators = {
|
|
3299
|
-
variantsChange: [{ type: Output }]
|
|
3403
|
+
variantsChange: [{ type: Output }],
|
|
3404
|
+
groupNameInputs: [{ type: ViewChildren, args: ['optionGroupName', { read: ElementRef },] }]
|
|
3300
3405
|
};
|
|
3301
3406
|
|
|
3302
3407
|
const OPTION_VALUE_INPUT_VALUE_ACCESSOR = {
|
|
@@ -3308,10 +3413,18 @@ class OptionValueInputComponent {
|
|
|
3308
3413
|
constructor(changeDetector) {
|
|
3309
3414
|
this.changeDetector = changeDetector;
|
|
3310
3415
|
this.groupName = '';
|
|
3416
|
+
this.add = new EventEmitter();
|
|
3417
|
+
this.remove = new EventEmitter();
|
|
3418
|
+
this.edit = new EventEmitter();
|
|
3311
3419
|
this.disabled = false;
|
|
3312
3420
|
this.input = '';
|
|
3313
3421
|
this.isFocussed = false;
|
|
3314
3422
|
this.lastSelected = false;
|
|
3423
|
+
this.editingIndex = -1;
|
|
3424
|
+
}
|
|
3425
|
+
get optionValues() {
|
|
3426
|
+
var _a, _b;
|
|
3427
|
+
return (_b = (_a = this.formValue) !== null && _a !== void 0 ? _a : this.options) !== null && _b !== void 0 ? _b : [];
|
|
3315
3428
|
}
|
|
3316
3429
|
registerOnChange(fn) {
|
|
3317
3430
|
this.onChangeFn = fn;
|
|
@@ -3324,15 +3437,42 @@ class OptionValueInputComponent {
|
|
|
3324
3437
|
this.changeDetector.markForCheck();
|
|
3325
3438
|
}
|
|
3326
3439
|
writeValue(obj) {
|
|
3327
|
-
this.
|
|
3440
|
+
this.formValue = obj || [];
|
|
3328
3441
|
}
|
|
3329
3442
|
focus() {
|
|
3330
3443
|
this.textArea.nativeElement.focus();
|
|
3331
3444
|
}
|
|
3445
|
+
editName(index, event) {
|
|
3446
|
+
var _a;
|
|
3447
|
+
const optionValue = this.optionValues[index];
|
|
3448
|
+
if (!optionValue.locked && !optionValue.id) {
|
|
3449
|
+
event.cancelBubble = true;
|
|
3450
|
+
this.editingIndex = index;
|
|
3451
|
+
const input = (_a = this.nameInputs.get(index)) === null || _a === void 0 ? void 0 : _a.nativeElement;
|
|
3452
|
+
setTimeout(() => input === null || input === void 0 ? void 0 : input.focus());
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
updateOption(index, event) {
|
|
3456
|
+
const optionValue = this.optionValues[index];
|
|
3457
|
+
const newName = event.target.value;
|
|
3458
|
+
if (optionValue) {
|
|
3459
|
+
if (newName) {
|
|
3460
|
+
optionValue.name = newName;
|
|
3461
|
+
this.edit.emit({ index, option: optionValue });
|
|
3462
|
+
}
|
|
3463
|
+
this.editingIndex = -1;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3332
3466
|
removeOption(option) {
|
|
3467
|
+
var _a;
|
|
3333
3468
|
if (!option.locked) {
|
|
3334
|
-
|
|
3335
|
-
|
|
3469
|
+
if (this.formValue) {
|
|
3470
|
+
this.formValue = (_a = this.formValue) === null || _a === void 0 ? void 0 : _a.filter(o => o.name !== option.name);
|
|
3471
|
+
this.onChangeFn(this.formValue);
|
|
3472
|
+
}
|
|
3473
|
+
else {
|
|
3474
|
+
this.remove.emit(option);
|
|
3475
|
+
}
|
|
3336
3476
|
}
|
|
3337
3477
|
}
|
|
3338
3478
|
handleKey(event) {
|
|
@@ -3360,9 +3500,17 @@ class OptionValueInputComponent {
|
|
|
3360
3500
|
this.addOptionValue();
|
|
3361
3501
|
}
|
|
3362
3502
|
addOptionValue() {
|
|
3363
|
-
|
|
3503
|
+
const options = this.parseInputIntoOptions(this.input);
|
|
3504
|
+
if (!this.formValue && this.options) {
|
|
3505
|
+
for (const option of options) {
|
|
3506
|
+
this.add.emit(option);
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
else {
|
|
3510
|
+
this.formValue = unique([...this.formValue, ...options]);
|
|
3511
|
+
this.onChangeFn(this.formValue);
|
|
3512
|
+
}
|
|
3364
3513
|
this.input = '';
|
|
3365
|
-
this.onChangeFn(this.options);
|
|
3366
3514
|
}
|
|
3367
3515
|
parseInputIntoOptions(input) {
|
|
3368
3516
|
return input
|
|
@@ -3372,18 +3520,19 @@ class OptionValueInputComponent {
|
|
|
3372
3520
|
.map(s => ({ name: s, locked: false }));
|
|
3373
3521
|
}
|
|
3374
3522
|
removeLastOption() {
|
|
3375
|
-
if (
|
|
3376
|
-
|
|
3523
|
+
if (this.optionValues.length) {
|
|
3524
|
+
const option = this.optionValues[this.optionValues.length - 1];
|
|
3525
|
+
this.removeOption(option);
|
|
3377
3526
|
}
|
|
3378
3527
|
}
|
|
3379
3528
|
}
|
|
3380
3529
|
OptionValueInputComponent.decorators = [
|
|
3381
3530
|
{ type: Component, args: [{
|
|
3382
3531
|
selector: 'vdr-option-value-input',
|
|
3383
|
-
template: "<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 <
|
|
3532
|
+
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",
|
|
3384
3533
|
changeDetection: ChangeDetectionStrategy.Default,
|
|
3385
3534
|
providers: [OPTION_VALUE_INPUT_VALUE_ACCESSOR],
|
|
3386
|
-
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"]
|
|
3535
|
+
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"]
|
|
3387
3536
|
},] }
|
|
3388
3537
|
];
|
|
3389
3538
|
OptionValueInputComponent.ctorParameters = () => [
|
|
@@ -3391,7 +3540,13 @@ OptionValueInputComponent.ctorParameters = () => [
|
|
|
3391
3540
|
];
|
|
3392
3541
|
OptionValueInputComponent.propDecorators = {
|
|
3393
3542
|
groupName: [{ type: Input }],
|
|
3394
|
-
textArea: [{ type: ViewChild, args: ['textArea', { static: true },] }]
|
|
3543
|
+
textArea: [{ type: ViewChild, args: ['textArea', { static: true },] }],
|
|
3544
|
+
nameInputs: [{ type: ViewChildren, args: ['editNameInput', { read: ElementRef },] }],
|
|
3545
|
+
options: [{ type: Input }],
|
|
3546
|
+
add: [{ type: Output }],
|
|
3547
|
+
remove: [{ type: Output }],
|
|
3548
|
+
edit: [{ type: Output }],
|
|
3549
|
+
disabled: [{ type: Input }]
|
|
3395
3550
|
};
|
|
3396
3551
|
|
|
3397
3552
|
class UpdateProductOptionDialogComponent {
|