@vendure/admin-ui 1.5.2 → 1.6.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 (116) hide show
  1. package/bundles/vendure-admin-ui-catalog.umd.js +206 -172
  2. package/bundles/vendure-admin-ui-catalog.umd.js.map +1 -1
  3. package/bundles/vendure-admin-ui-core.umd.js +2333 -1860
  4. package/bundles/vendure-admin-ui-core.umd.js.map +1 -1
  5. package/bundles/vendure-admin-ui-dashboard.umd.js +2 -2
  6. package/bundles/vendure-admin-ui-login.umd.js +2 -2
  7. package/bundles/vendure-admin-ui-login.umd.js.map +1 -1
  8. package/bundles/vendure-admin-ui-marketing.umd.js +1 -1
  9. package/bundles/vendure-admin-ui-marketing.umd.js.map +1 -1
  10. package/bundles/vendure-admin-ui-order.umd.js +1 -1
  11. package/bundles/vendure-admin-ui-order.umd.js.map +1 -1
  12. package/catalog/components/collection-contents/collection-contents.component.d.ts +7 -2
  13. package/catalog/components/collection-detail/collection-detail.component.d.ts +12 -4
  14. package/catalog/components/collection-list/collection-list.component.d.ts +2 -0
  15. package/catalog/components/collection-tree/array-to-tree.d.ts +1 -1
  16. package/catalog/components/collection-tree/collection-tree-node.component.d.ts +5 -1
  17. package/catalog/components/collection-tree/collection-tree.component.d.ts +1 -0
  18. package/catalog/providers/product-detail/product-detail.service.d.ts +2 -2
  19. package/catalog/public_api.d.ts +0 -1
  20. package/catalog/vendure-admin-ui-catalog.metadata.json +1 -1
  21. package/core/common/generated-types.d.ts +32 -3
  22. package/core/common/utilities/selection-manager.d.ts +23 -0
  23. package/core/common/version.d.ts +1 -1
  24. package/core/components/app-shell/app-shell.component.d.ts +1 -0
  25. package/core/data/definitions/collection-definitions.d.ts +1 -0
  26. package/core/data/providers/collection-data.service.d.ts +6 -2
  27. package/core/providers/local-storage/local-storage.service.d.ts +1 -0
  28. package/core/public_api.d.ts +5 -0
  29. package/core/shared/components/asset-gallery/asset-gallery.component.d.ts +21 -6
  30. package/core/shared/components/configurable-input/configurable-input.component.d.ts +7 -2
  31. package/core/shared/components/product-multi-selector-dialog/product-multi-selector-dialog.component.d.ts +35 -0
  32. package/{catalog → core/shared}/components/product-search-input/product-search-input.component.d.ts +1 -1
  33. package/core/shared/components/select-toggle/select-toggle.component.d.ts +1 -0
  34. package/core/shared/dynamic-form-inputs/combination-mode-form-input/combination-mode-form-input.component.d.ts +25 -0
  35. package/core/shared/dynamic-form-inputs/product-multi-selector-form-input/product-multi-selector-form-input.component.d.ts +20 -0
  36. package/core/shared/dynamic-form-inputs/register-dynamic-input-components.d.ts +3 -1
  37. package/core/shared/dynamic-form-inputs/relation-form-input/asset/relation-asset-input.component.d.ts +5 -2
  38. package/core/vendure-admin-ui-core.metadata.json +1 -1
  39. package/dashboard/vendure-admin-ui-dashboard.metadata.json +1 -1
  40. package/esm2015/catalog/catalog.module.js +1 -3
  41. package/esm2015/catalog/components/assets/assets.component.js +1 -1
  42. package/esm2015/catalog/components/collection-contents/collection-contents.component.js +51 -14
  43. package/esm2015/catalog/components/collection-detail/collection-detail.component.js +67 -29
  44. package/esm2015/catalog/components/collection-list/collection-list.component.js +30 -4
  45. package/esm2015/catalog/components/collection-tree/array-to-tree.js +3 -3
  46. package/esm2015/catalog/components/collection-tree/collection-tree-node.component.js +27 -4
  47. package/esm2015/catalog/components/collection-tree/collection-tree.component.js +4 -2
  48. package/esm2015/catalog/components/product-detail/product-detail.component.js +1 -1
  49. package/esm2015/catalog/components/product-list/product-list.component.js +3 -3
  50. package/esm2015/catalog/components/product-variants-list/product-variants-list.component.js +1 -1
  51. package/esm2015/catalog/public_api.js +1 -2
  52. package/esm2015/core/app.component.module.js +1 -1
  53. package/esm2015/core/common/base-detail.component.js +1 -1
  54. package/esm2015/core/common/deactivate-aware.js +1 -1
  55. package/esm2015/core/common/generated-types.js +1 -1
  56. package/esm2015/core/common/introspection-result.js +255 -189
  57. package/esm2015/core/common/utilities/selection-manager.js +64 -0
  58. package/esm2015/core/common/version.js +2 -2
  59. package/esm2015/core/components/app-shell/app-shell.component.js +4 -3
  60. package/esm2015/core/core.module.js +1 -1
  61. package/esm2015/core/data/definitions/collection-definitions.js +18 -1
  62. package/esm2015/core/data/definitions/order-definitions.js +2 -1
  63. package/esm2015/core/data/definitions/shared-definitions.js +29 -28
  64. package/esm2015/core/data/providers/collection-data.service.js +5 -2
  65. package/esm2015/core/providers/local-storage/local-storage.service.js +1 -1
  66. package/esm2015/core/public_api.js +6 -1
  67. package/esm2015/core/shared/components/asset-gallery/asset-gallery.component.js +24 -42
  68. package/esm2015/core/shared/components/configurable-input/configurable-input.component.js +13 -3
  69. package/esm2015/core/shared/components/help-tooltip/help-tooltip.component.js +1 -1
  70. package/esm2015/core/shared/components/product-multi-selector-dialog/product-multi-selector-dialog.component.js +129 -0
  71. package/esm2015/core/shared/components/product-search-input/product-search-input.component.js +104 -0
  72. package/esm2015/core/shared/components/rich-text-editor/rich-text-editor.component.js +1 -1
  73. package/esm2015/core/shared/components/select-toggle/select-toggle.component.js +5 -3
  74. package/esm2015/core/shared/dynamic-form-inputs/combination-mode-form-input/combination-mode-form-input.component.js +45 -0
  75. package/esm2015/core/shared/dynamic-form-inputs/product-multi-selector-form-input/product-multi-selector-form-input.component.js +53 -0
  76. package/esm2015/core/shared/dynamic-form-inputs/register-dynamic-input-components.js +5 -1
  77. package/esm2015/core/shared/dynamic-form-inputs/relation-form-input/asset/relation-asset-input.component.js +8 -7
  78. package/esm2015/core/shared/shared.module.js +9 -1
  79. package/esm2015/dashboard/components/dashboard/dashboard.component.js +1 -1
  80. package/esm2015/dashboard/widgets/order-summary-widget/order-summary-widget.component.js +1 -1
  81. package/esm2015/login/components/login/login.component.js +3 -3
  82. package/esm2015/marketing/components/promotion-detail/promotion-detail.component.js +2 -2
  83. package/esm2015/order/components/order-list/order-list.component.js +2 -2
  84. package/fesm2015/vendure-admin-ui-catalog.js +181 -157
  85. package/fesm2015/vendure-admin-ui-catalog.js.map +1 -1
  86. package/fesm2015/vendure-admin-ui-core.js +2156 -1691
  87. package/fesm2015/vendure-admin-ui-core.js.map +1 -1
  88. package/fesm2015/vendure-admin-ui-dashboard.js +2 -2
  89. package/fesm2015/vendure-admin-ui-login.js +2 -2
  90. package/fesm2015/vendure-admin-ui-login.js.map +1 -1
  91. package/fesm2015/vendure-admin-ui-marketing.js +1 -1
  92. package/fesm2015/vendure-admin-ui-marketing.js.map +1 -1
  93. package/fesm2015/vendure-admin-ui-order.js +1 -1
  94. package/fesm2015/vendure-admin-ui-order.js.map +1 -1
  95. package/login/vendure-admin-ui-login.metadata.json +1 -1
  96. package/marketing/vendure-admin-ui-marketing.metadata.json +1 -1
  97. package/order/vendure-admin-ui-order.metadata.json +1 -1
  98. package/package.json +2 -2
  99. package/static/i18n-messages/cs.json +9 -0
  100. package/static/i18n-messages/de.json +9 -0
  101. package/static/i18n-messages/en.json +10 -1
  102. package/static/i18n-messages/es.json +9 -0
  103. package/static/i18n-messages/fr.json +9 -0
  104. package/static/i18n-messages/it.json +9 -0
  105. package/static/i18n-messages/pl.json +9 -0
  106. package/static/i18n-messages/pt_BR.json +9 -0
  107. package/static/i18n-messages/pt_PT.json +9 -0
  108. package/static/i18n-messages/ru.json +9 -0
  109. package/static/i18n-messages/uk.json +9 -0
  110. package/static/i18n-messages/zh_Hans.json +9 -0
  111. package/static/i18n-messages/zh_Hant.json +9 -0
  112. package/static/styles/global/_forms.scss +4 -5
  113. package/static/styles/global/_overrides.scss +5 -1
  114. package/static/styles/theme/default.scss +13 -1
  115. package/static/theme.min.css +1 -1
  116. package/esm2015/catalog/components/product-search-input/product-search-input.component.js +0 -104
@@ -3,11 +3,11 @@ import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, Injec
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
- import { BaseDetailComponent, ServerConfigService, NotificationService, DataService, BaseListComponent, SortOrder, LogicalOperator, DeletionResult, ModalService, Permission, unicodePatternValidator, findTranslation, getConfigArgValue, createUpdatedTranslatable, encodeConfigArgValue, FacetValueSelectorComponent, flattenFacetValues, JobState, JobQueueService, getDefaultUiLanguage, BaseEntityResolver, AssetType, createResolveData, CanDeactivateDetailGuard, detailBreadcrumb, AssetPickerDialogComponent, AssetPreviewDialogComponent, SingleSearchSelectionModelFactory, GlobalFlag, SharedModule } from '@vendure/admin-ui/core';
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, take, mergeMap, shareReplay, distinctUntilChanged, tap, mapTo, filter, startWith, skipUntil, skip, withLatestFrom, delay } from 'rxjs/operators';
8
+ import { map, debounceTime, takeUntil, finalize, switchMap, filter, take, mergeMap, shareReplay, distinctUntilChanged, tap, mapTo, startWith, skipUntil, skip, withLatestFrom, delay, catchError } from 'rxjs/operators';
9
9
  import { FormGroup, FormControl, FormBuilder, Validators, FormArray, NG_VALUE_ACCESSOR } from '@angular/forms';
10
- import { BehaviorSubject, combineLatest, EMPTY, Subject, forkJoin, of, throwError, from, merge } from 'rxjs';
10
+ import { BehaviorSubject, combineLatest, EMPTY, Subject, merge, of, forkJoin, throwError, from } from 'rxjs';
11
11
  import { normalizeString } from '@vendure/common/lib/normalize-string';
12
12
  import { notNullOrUndefined, generateAllCombinations } from '@vendure/common/lib/shared-utils';
13
13
  import { SortOrder as SortOrder$1 } from '@vendure/common/lib/generated-shop-types';
@@ -17,7 +17,6 @@ import { unique } from '@vendure/common/lib/unique';
17
17
  import { __awaiter } from 'tslib';
18
18
  import { pick } from '@vendure/common/lib/pick';
19
19
  import { moveItemInArray } from '@angular/cdk/drag-drop';
20
- import { SELECTION_MODEL_FACTORY } from '@ng-select/ng-select';
21
20
 
22
21
  class AssetDetailComponent extends BaseDetailComponent {
23
22
  constructor(router, route, serverConfigService, notificationService, dataService, formBuilder) {
@@ -201,17 +200,21 @@ AssetListComponent.ctorParameters = () => [
201
200
  ];
202
201
 
203
202
  class CollectionDetailComponent extends BaseDetailComponent {
204
- constructor(router, route, serverConfigService, changeDetector, dataService, formBuilder, notificationService, modalService) {
203
+ constructor(router, route, serverConfigService, changeDetector, dataService, formBuilder, notificationService, modalService, localStorageService) {
204
+ var _a;
205
205
  super(route, router, serverConfigService, dataService);
206
206
  this.changeDetector = changeDetector;
207
207
  this.dataService = dataService;
208
208
  this.formBuilder = formBuilder;
209
209
  this.notificationService = notificationService;
210
210
  this.modalService = modalService;
211
+ this.localStorageService = localStorageService;
211
212
  this.assetChanges = {};
212
213
  this.filters = [];
213
214
  this.allFilters = [];
215
+ this.livePreview = false;
214
216
  this.updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];
217
+ this.filterRemoved$ = new Subject();
215
218
  this.customFields = this.getCustomFieldConfig('Collection');
216
219
  this.detailForm = this.formBuilder.group({
217
220
  name: ['', Validators.required],
@@ -221,18 +224,38 @@ class CollectionDetailComponent extends BaseDetailComponent {
221
224
  filters: this.formBuilder.array([]),
222
225
  customFields: this.formBuilder.group(this.customFields.reduce((hash, field) => (Object.assign(Object.assign({}, hash), { [field.name]: '' })), {})),
223
226
  });
227
+ this.livePreview = (_a = this.localStorageService.get('livePreviewCollectionContents')) !== null && _a !== void 0 ? _a : false;
224
228
  }
225
229
  ngOnInit() {
226
230
  this.init();
227
231
  this.dataService.collection.getCollectionFilters().single$.subscribe(res => {
228
232
  this.allFilters = res.collectionFilters;
229
233
  });
234
+ const filtersFormArray = this.detailForm.get('filters');
235
+ this.updatedFilters$ = merge(filtersFormArray.statusChanges, this.filterRemoved$).pipe(debounceTime(200), filter(() => filtersFormArray.touched), map(() => this.mapOperationsToInputs(this.filters, filtersFormArray.value).filter(_filter => {
236
+ // ensure all the arguments have valid values. E.g. a newly-added
237
+ // filter will not yet have valid values
238
+ for (const arg of _filter.arguments) {
239
+ if (arg.value === '') {
240
+ return false;
241
+ }
242
+ }
243
+ return true;
244
+ })));
245
+ this.parentId$ = this.route.paramMap.pipe(map(pm => pm.get('parentId') || undefined), switchMap(parentId => {
246
+ if (parentId) {
247
+ return of(parentId);
248
+ }
249
+ else {
250
+ return this.entity$.pipe(map(collection => { var _a; return (_a = collection.parent) === null || _a === void 0 ? void 0 : _a.id; }));
251
+ }
252
+ }));
230
253
  }
231
254
  ngOnDestroy() {
232
255
  this.destroy();
233
256
  }
234
- getFilterDefinition(filter) {
235
- return this.allFilters.find(f => f.code === filter.code);
257
+ getFilterDefinition(_filter) {
258
+ return this.allFilters.find(f => f.code === _filter.code);
236
259
  }
237
260
  assetsChanged() {
238
261
  return !!Object.values(this.assetChanges).length;
@@ -254,25 +277,24 @@ class CollectionDetailComponent extends BaseDetailComponent {
254
277
  }
255
278
  addFilter(collectionFilter) {
256
279
  const filtersArray = this.detailForm.get('filters');
257
- const index = filtersArray.value.findIndex(o => o.code === collectionFilter.code);
258
- if (index === -1) {
259
- const argsHash = collectionFilter.args.reduce((output, arg) => (Object.assign(Object.assign({}, output), { [arg.name]: getConfigArgValue(arg.value) })), {});
260
- filtersArray.push(this.formBuilder.control({
261
- code: collectionFilter.code,
262
- args: argsHash,
263
- }));
264
- this.filters.push({
265
- code: collectionFilter.code,
266
- args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),
267
- });
268
- }
280
+ const argsHash = collectionFilter.args.reduce((output, arg) => (Object.assign(Object.assign({}, output), { [arg.name]: getConfigArgValue(arg.value) })), {});
281
+ filtersArray.push(this.formBuilder.control({
282
+ code: collectionFilter.code,
283
+ args: argsHash,
284
+ }));
285
+ this.filters.push({
286
+ code: collectionFilter.code,
287
+ args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),
288
+ });
269
289
  }
270
- removeFilter(collectionFilter) {
290
+ removeFilter(index) {
271
291
  const filtersArray = this.detailForm.get('filters');
272
- const index = filtersArray.value.findIndex(o => o.code === collectionFilter.code);
273
292
  if (index !== -1) {
274
293
  filtersArray.removeAt(index);
294
+ filtersArray.markAsDirty();
295
+ filtersArray.markAsTouched();
275
296
  this.filters.splice(index, 1);
297
+ this.filterRemoved$.next();
276
298
  }
277
299
  }
278
300
  create() {
@@ -325,6 +347,13 @@ class CollectionDetailComponent extends BaseDetailComponent {
325
347
  canDeactivate() {
326
348
  return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;
327
349
  }
350
+ toggleLivePreview() {
351
+ this.livePreview = !this.livePreview;
352
+ this.localStorageService.set('livePreviewCollectionContents', this.livePreview);
353
+ }
354
+ trackByFn(index, item) {
355
+ return JSON.stringify(item);
356
+ }
328
357
  /**
329
358
  * Sets the values of the form on changes to the category or current language.
330
359
  */
@@ -336,7 +365,12 @@ class CollectionDetailComponent extends BaseDetailComponent {
336
365
  description: currentTranslation ? currentTranslation.description : '',
337
366
  visible: !entity.isPrivate,
338
367
  });
339
- entity.filters.forEach(f => this.addFilter(f));
368
+ const formArray = this.detailForm.get('filters');
369
+ if (formArray.length !== entity.filters.length) {
370
+ formArray.clear();
371
+ this.filters = [];
372
+ entity.filters.forEach(f => this.addFilter(f));
373
+ }
340
374
  if (this.customFields.length) {
341
375
  this.setCustomFieldFormValues(this.customFields, this.detailForm.get(['customFields']), entity, currentTranslation);
342
376
  }
@@ -368,10 +402,12 @@ class CollectionDetailComponent extends BaseDetailComponent {
368
402
  return operations.map((o, i) => {
369
403
  return {
370
404
  code: o.code,
371
- arguments: Object.values(formValueOperations[i].args).map((value, j) => ({
372
- name: o.args[j].name,
373
- value: encodeConfigArgValue(value),
374
- })),
405
+ arguments: Object.entries(formValueOperations[i].args).map(([name, value], j) => {
406
+ return {
407
+ name,
408
+ value: encodeConfigArgValue(value),
409
+ };
410
+ }),
375
411
  };
376
412
  });
377
413
  }
@@ -379,9 +415,9 @@ class CollectionDetailComponent extends BaseDetailComponent {
379
415
  CollectionDetailComponent.decorators = [
380
416
  { type: Component, args: [{
381
417
  selector: 'vdr-collection-detail',
382
- template: "<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(detailForm.invalid || detailForm.pristine) && !assetsChanged()\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as category\">\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.visible; else private\">{{ 'catalog.public' | translate }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: ('catalog.slug-pattern-error' | translate) }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Collection\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"collection-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"category.assets\"\r\n [featuredAsset]=\"category.featuredAsset\"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n </div>\r\n </div>\r\n <div class=\"clr-row\" formArrayName=\"filters\">\r\n <div class=\"clr-col\">\r\n <label>{{ 'catalog.filters' | translate }}</label>\r\n <ng-container *ngFor=\"let filter of filters; index as i\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter($event)\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n\r\n <div *vdrIfPermissions=\"updatePermission\">\r\n <vdr-dropdown>\r\n <button class=\"btn btn-outline\" vdrDropdownTrigger>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'marketing.add-condition' | translate }}\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-left\">\r\n <button\r\n *ngFor=\"let filter of allFilters\"\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"addFilter(filter)\"\r\n >\r\n {{ filter.description }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n <div class=\"clr-col\">\r\n <vdr-collection-contents [collectionId]=\"id\" #collectionContents>\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n",
418
+ template: "<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"(detailForm.invalid || detailForm.pristine) && !assetsChanged()\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"entity$ | async as category\">\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <vdr-form-field [label]=\"'catalog.visibility' | translate\" for=\"visibility\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.visible; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: ('catalog.slug-pattern-error' | translate) }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Collection\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"collection-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"category.assets\"\r\n [featuredAsset]=\"category.featuredAsset\"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n </div>\r\n </div>\r\n <div class=\"clr-row\" formArrayName=\"filters\">\r\n <div class=\"clr-col\">\r\n <label>{{ 'catalog.filters' | translate }}</label>\r\n <ng-container *ngFor=\"let filter of filters; index as i; trackBy:trackByFn\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter(i)\"\r\n [position]=\"i\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n\r\n <div *vdrIfPermissions=\"updatePermission\">\r\n <vdr-dropdown>\r\n <button class=\"btn btn-outline\" vdrDropdownTrigger>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'marketing.add-condition' | translate }}\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-left\">\r\n <button\r\n *ngFor=\"let filter of allFilters\"\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"addFilter(filter)\"\r\n >\r\n {{ filter.description }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n <div class=\"clr-col\">\r\n <vdr-collection-contents\r\n [collectionId]=\"id\"\r\n [parentId]=\"parentId$ | async\"\r\n [updatedFilters]=\"updatedFilters$ | async\"\r\n [previewUpdatedFilters]=\"livePreview\"\r\n #collectionContents\r\n >\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <clr-checkbox-wrapper [class.disabled]=\"detailForm.get('filters')?.pristine\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [disabled]=\"detailForm.get('filters')?.pristine\"\r\n [ngModel]=\"livePreview\"\r\n (ngModelChange)=\"toggleLivePreview()\"\r\n />\r\n <label>{{ 'catalog.live-preview-contents' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n",
383
419
  changeDetection: ChangeDetectionStrategy.OnPush,
384
- styles: [".visible-toggle{margin-top:-3px!important}\n"]
420
+ styles: [".visible-toggle{margin-top:-3px!important}clr-checkbox-wrapper{transition:opacity .3s}clr-checkbox-wrapper.disabled{opacity:.5}\n"]
385
421
  },] }
386
422
  ];
387
423
  CollectionDetailComponent.ctorParameters = () => [
@@ -392,7 +428,8 @@ CollectionDetailComponent.ctorParameters = () => [
392
428
  { type: DataService },
393
429
  { type: FormBuilder },
394
430
  { type: NotificationService },
395
- { type: ModalService }
431
+ { type: ModalService },
432
+ { type: LocalStorageService }
396
433
  ];
397
434
  CollectionDetailComponent.propDecorators = {
398
435
  contentsComponent: [{ type: ViewChild, args: ['collectionContents',] }]
@@ -408,12 +445,16 @@ class CollectionListComponent {
408
445
  this.serverConfigService = serverConfigService;
409
446
  this.filterTermControl = new FormControl('');
410
447
  this.expandAll = false;
448
+ this.expandedIds = [];
411
449
  this.destroy$ = new Subject();
412
450
  }
413
451
  ngOnInit() {
452
+ var _a, _b;
414
453
  this.queryResult = this.dataService.collection.getCollections(1000, 0).refetchOnChannelChange();
415
454
  this.items$ = this.queryResult.mapStream(data => data.collections.items).pipe(shareReplay(1));
416
455
  this.activeCollectionId$ = this.route.paramMap.pipe(map(pm => pm.get('contents')), distinctUntilChanged());
456
+ this.expandedIds = (_b = (_a = this.route.snapshot.queryParamMap.get('expanded')) === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
457
+ this.expandAll = this.route.snapshot.queryParamMap.get('expanded') === 'all';
417
458
  this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(map(([id, collections]) => {
418
459
  if (id) {
419
460
  const match = collections.find(c => c.id === id);
@@ -428,13 +469,34 @@ class CollectionListComponent {
428
469
  .pipe(tap(() => this.refresh()));
429
470
  this.filterTermControl.valueChanges
430
471
  .pipe(debounceTime(250), takeUntil(this.destroy$))
472
+ .subscribe(term => {
473
+ this.router.navigate(['./'], {
474
+ queryParams: {
475
+ q: term || undefined,
476
+ },
477
+ queryParamsHandling: 'merge',
478
+ relativeTo: this.route,
479
+ });
480
+ });
481
+ this.route.queryParamMap
482
+ .pipe(map(qpm => qpm.get('q')), distinctUntilChanged(), takeUntil(this.destroy$))
431
483
  .subscribe(() => this.refresh());
484
+ this.filterTermControl.patchValue(this.route.snapshot.queryParamMap.get('q'));
432
485
  }
433
486
  ngOnDestroy() {
434
487
  this.queryResult.completed$.next();
435
488
  this.destroy$.next(undefined);
436
489
  this.destroy$.complete();
437
490
  }
491
+ toggleExpandAll() {
492
+ this.router.navigate(['./'], {
493
+ queryParams: {
494
+ expanded: this.expandAll ? 'all' : undefined,
495
+ },
496
+ queryParamsHandling: 'merge',
497
+ relativeTo: this.route,
498
+ });
499
+ }
438
500
  onRearrange(event) {
439
501
  this.dataService.collection.moveCollection([event]).subscribe({
440
502
  next: () => {
@@ -480,12 +542,13 @@ class CollectionListComponent {
480
542
  this.dataService.client.setContentLanguage(code).subscribe();
481
543
  }
482
544
  refresh() {
545
+ const filterTerm = this.route.snapshot.queryParamMap.get('q');
483
546
  this.queryResult.ref.refetch({
484
- options: Object.assign({ skip: 0, take: 1000 }, (this.filterTermControl.value
547
+ options: Object.assign({ skip: 0, take: 1000 }, (filterTerm
485
548
  ? {
486
549
  filter: {
487
550
  name: {
488
- contains: this.filterTermControl.value,
551
+ contains: filterTerm,
489
552
  },
490
553
  },
491
554
  }
@@ -496,7 +559,7 @@ class CollectionListComponent {
496
559
  CollectionListComponent.decorators = [
497
560
  { type: Component, args: [{
498
561
  selector: 'vdr-collection-list',
499
- template: "<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex center wrap\">\r\n <vdr-language-selector\r\n class=\"mt2\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n <clr-checkbox-wrapper\r\n class=\"expand-all-toggle ml3\"\r\n [ngClass]=\"(availableLanguages$ | async)?.length === 1 ? 'mt3' : 'mt1'\"\r\n >\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"expandAll\" />\r\n <label>{{ 'catalog.expand-all-collections' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <input\r\n type='text'\r\n name='searchTerm'\r\n [formControl]='filterTermControl'\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class='clr-input search-input ml4'\r\n />\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<div class=\"collection-wrapper\">\r\n <vdr-collection-tree\r\n [collections]=\"items$ | async\"\r\n [activeCollectionId]=\"activeCollectionId$ | async\"\r\n [expandAll]=\"expandAll\"\r\n (rearrange)=\"onRearrange($event)\"\r\n (deleteCollection)=\"deleteCollection($event)\"\r\n ></vdr-collection-tree>\r\n\r\n <div class=\"collection-contents\" [class.expanded]=\"activeCollectionId$ | async\">\r\n <vdr-collection-contents [collectionId]=\"activeCollectionId$ | async\">\r\n <ng-template let-count>\r\n <div class=\"collection-title\">\r\n {{ activeCollectionTitle$ | async }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <button type=\"button\" class=\"close-button\" (click)=\"closeContents()\">\r\n <clr-icon shape=\"close\"></clr-icon>\r\n </button>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n</div>\r\n",
562
+ template: "<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex center wrap\">\r\n <vdr-language-selector\r\n class=\"mt2\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n <clr-checkbox-wrapper\r\n class=\"expand-all-toggle ml3\"\r\n [ngClass]=\"(availableLanguages$ | async)?.length === 1 ? 'mt3' : 'mt1'\"\r\n >\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"expandAll\" (change)=\"toggleExpandAll()\"/>\r\n <label>{{ 'catalog.expand-all-collections' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <input\r\n type='text'\r\n name='searchTerm'\r\n [formControl]='filterTermControl'\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class='clr-input search-input ml4'\r\n />\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<div class=\"collection-wrapper\">\r\n <vdr-collection-tree\r\n [collections]=\"items$ | async\"\r\n [activeCollectionId]=\"activeCollectionId$ | async\"\r\n [expandAll]=\"expandAll\"\r\n [expandedIds]=\"expandedIds\"\r\n (rearrange)=\"onRearrange($event)\"\r\n (deleteCollection)=\"deleteCollection($event)\"\r\n ></vdr-collection-tree>\r\n\r\n <div class=\"collection-contents\" [class.expanded]=\"activeCollectionId$ | async\">\r\n <vdr-collection-contents [collectionId]=\"activeCollectionId$ | async\">\r\n <ng-template let-count>\r\n <div class=\"collection-title\">\r\n {{ activeCollectionTitle$ | async }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <button type=\"button\" class=\"close-button\" (click)=\"closeContents()\">\r\n <clr-icon shape=\"close\"></clr-icon>\r\n </button>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n</div>\r\n",
500
563
  changeDetection: ChangeDetectionStrategy.OnPush,
501
564
  styles: [":host{height:100%;display:flex;flex-direction:column}.expand-all-toggle{display:block}.collection-wrapper{display:flex;height:calc(100% - 50px)}.collection-wrapper vdr-collection-tree{flex:1;height:100%;overflow:auto}.collection-wrapper .collection-contents{height:100%;width:0;opacity:0;visibility:hidden;overflow:auto;transition:width .3s,opacity .2s .3s,visibility 0s .3s}.collection-wrapper .collection-contents.expanded{width:30vw;visibility:visible;opacity:1;padding-left:12px}.collection-wrapper .collection-contents .close-button{margin:0;background:none;border:none;cursor:pointer}.paging-controls{padding-top:6px;border-top:1px solid var(--color-component-border-100);display:flex;justify-content:space-between}\n"]
502
565
  },] }
@@ -1774,7 +1837,7 @@ ProductDetailComponent.decorators = [
1774
1837
  selector: 'vdr-product-detail',
1775
1838
  template: "<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex clr-flex-row\">\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n <clr-toggle-wrapper *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\">\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n [formControl]=\"detailForm.get(['product', 'enabled'])\"\r\n />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n <vdr-language-selector\r\n [disabled]=\"isNew$ | async\"\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-detail\"></vdr-action-bar-items>\r\n <button\r\n class=\"btn btn-primary\"\r\n *ngIf=\"isNew$ | async; else updateButton\"\r\n (click)=\"create()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine || !variantsToCreateAreValid()\"\r\n >\r\n {{ 'common.create' | translate }}\r\n </button>\r\n <ng-template #updateButton>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"\r\n (detailForm.invalid || detailForm.pristine) && !assetsChanged() && !variantAssetsChanged()\r\n \"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </ng-template>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"product$ | async as product\">\r\n <button type=\"submit\" hidden x-data=\"prevents enter key from triggering other buttons\"></button>\r\n <clr-tabs>\r\n <clr-tab>\r\n <button clrTabLink (click)=\"navigateToTab('details')\">\r\n {{ 'catalog.product-details' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'details'\">\r\n <div class=\"clr-row\">\r\n <div class=\"clr-col\">\r\n <section class=\"form-block\" formGroupName=\"product\">\r\n <ng-container *ngIf=\"!(isNew$ | async)\">\r\n <ng-container *vdrIfMultichannel>\r\n <vdr-form-item\r\n [label]=\"'common.channels' | translate\"\r\n *vdrIfDefaultChannelActive\r\n >\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of productChannels$ | async\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n (iconClick)=\"removeFromChannel(channel.id)\"\r\n >\r\n <vdr-channel-badge\r\n [channelCode]=\"channel.code\"\r\n ></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel()\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </vdr-form-item>\r\n </ng-container>\r\n </ng-container>\r\n <vdr-form-field [label]=\"'catalog.product-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n (input)=\"updateSlug($event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <div\r\n class=\"auto-rename-wrapper\"\r\n [class.visible]=\"\r\n (isNew$ | async) === false && detailForm.get(['product', 'name'])?.dirty\r\n \"\r\n >\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n formControlName=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{\r\n 'catalog.auto-update-product-variant-name' | translate\r\n }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <vdr-form-field\r\n [label]=\"'catalog.slug' | translate\"\r\n for=\"slug\"\r\n [errors]=\"{ pattern: 'catalog.slug-pattern-error' | translate }\"\r\n >\r\n <input\r\n id=\"slug\"\r\n type=\"text\"\r\n formControlName=\"slug\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-rich-text-editor\r\n formControlName=\"description\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n [label]=\"'common.description' | translate\"\r\n ></vdr-rich-text-editor>\r\n\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"Product\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['product', 'customFields'])\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n <vdr-custom-detail-component-host\r\n locationId=\"product-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n </div>\r\n <div class=\"clr-col-md-auto\">\r\n <vdr-assets\r\n [assets]=\"assetChanges.assets || product.assets\"\r\n [featuredAsset]=\"assetChanges.featuredAsset || product.featuredAsset\"\r\n [updatePermissions]=\"updatePermissions\"\r\n (change)=\"assetChanges = $event\"\r\n ></vdr-assets>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of facetValues$ | async\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"['UpdateCatalog', 'UpdateProduct'] | hasPermission\"\r\n (remove)=\"removeProductFacetValue(facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary\"\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n (click)=\"selectProductFacetValue()\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div *ngIf=\"isNew$ | async\">\r\n <h4>{{ 'catalog.product-variants' | translate }}</h4>\r\n <vdr-generate-product-variants\r\n (variantsChange)=\"createVariantsConfig = $event\"\r\n ></vdr-generate-product-variants>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n <clr-tab *ngIf=\"!(isNew$ | async)\">\r\n <button clrTabLink (click)=\"navigateToTab('variants')\">\r\n {{ 'catalog.product-variants' | translate }}\r\n </button>\r\n <clr-tab-content *clrIfActive=\"(activeTab$ | async) === 'variants'\">\r\n <section class=\"form-block\">\r\n <div class=\"view-mode\">\r\n <div class=\"btn-group\">\r\n <button\r\n class=\"btn btn-secondary-outline\"\r\n (click)=\"variantDisplayMode = 'card'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'card'\"\r\n >\r\n <clr-icon shape=\"list\"></clr-icon>\r\n {{ 'catalog.display-variant-cards' | translate }}\r\n </button>\r\n <button\r\n class=\"btn\"\r\n (click)=\"variantDisplayMode = 'table'\"\r\n [class.btn-primary]=\"variantDisplayMode === 'table'\"\r\n >\r\n <clr-icon shape=\"table\"></clr-icon>\r\n {{ 'catalog.display-variant-table' | translate }}\r\n </button>\r\n </div>\r\n <div class=\"variant-filter\">\r\n <input\r\n [formControl]=\"filterInput\"\r\n [placeholder]=\"'catalog.filter-by-name-or-sku' | translate\"\r\n />\r\n <button class=\"icon-button\" (click)=\"filterInput.setValue('')\">\r\n <clr-icon shape=\"times\"></clr-icon>\r\n </button>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <a\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateProduct']\"\r\n [routerLink]=\"['./', 'manage-variants']\"\r\n class=\"btn btn-secondary edit-variants-btn\"\r\n >\r\n <clr-icon shape=\"add-text\"></clr-icon>\r\n {{ 'catalog.manage-variants' | translate }}\r\n </a>\r\n </div>\r\n\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n\r\n <vdr-product-variants-table\r\n *ngIf=\"variantDisplayMode === 'table'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n ></vdr-product-variants-table>\r\n <vdr-product-variants-list\r\n *ngIf=\"variantDisplayMode === 'card'\"\r\n [variants]=\"variants$ | async\"\r\n [paginationConfig]=\"paginationConfig$ | async\"\r\n [channelPriceIncludesTax]=\"channelPriceIncludesTax$ | async\"\r\n [facets]=\"facets$ | async\"\r\n [optionGroups]=\"product.optionGroups\"\r\n [productVariantsFormArray]=\"detailForm.get('variants')\"\r\n [taxCategories]=\"taxCategories$ | async\"\r\n [customFields]=\"customVariantFields\"\r\n [customOptionFields]=\"customOptionFields\"\r\n [activeLanguage]=\"languageCode$ | async\"\r\n [pendingAssetChanges]=\"variantAssetChanges\"\r\n (assignToChannel)=\"assignVariantToChannel($event)\"\r\n (removeFromChannel)=\"removeVariantFromChannel($event)\"\r\n (assetChange)=\"variantAssetChange($event)\"\r\n (updateProductOption)=\"updateProductOption($event)\"\r\n (selectionChange)=\"selectedVariantIds = $event\"\r\n (selectFacetValueClick)=\"selectVariantFacetValue($event)\"\r\n ></vdr-product-variants-list>\r\n </section>\r\n <div class=\"pagination-row mt4\" *ngIf=\"10 < (paginationConfig$ | async)?.totalItems\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [id]=\"(paginationConfig$ | async)?.id\"\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (pageChange)=\"setPage($event)\"\r\n ></vdr-pagination-controls>\r\n </div>\r\n </clr-tab-content>\r\n </clr-tab>\r\n </clr-tabs>\r\n</form>\r\n",
1776
1839
  changeDetection: ChangeDetectionStrategy.OnPush,
1777
- styles: [":host ::ng-deep trix-toolbar{top:24px}.facets{margin-top:12px;display:flex;flex-wrap:wrap;align-items:center}@media screen and (min-width: 768px){.facets{max-width:340px}}vdr-action-bar clr-toggle-wrapper{margin-top:12px}.variant-filter{flex:1;display:flex}.variant-filter input{flex:1;max-width:initial;border-radius:3px 0 0 3px!important}.variant-filter .icon-button{border:1px solid var(--color-component-border-300);background-color:var(--color-component-bg-100);border-radius:0 3px 3px 0;border-left:none}.group-name{padding-right:6px}.view-mode{display:flex;justify-content:flex-end;align-items:center}.edit-variants-btn{margin-top:0}.channel-assignment{flex-wrap:wrap}.auto-rename-wrapper{overflow:hidden;max-height:0;padding-left:9.5rem;margin-bottom:0;transition:max-height .2s,margin-bottom .2s}.auto-rename-wrapper.visible{max-height:24px;margin-bottom:12px}.pagination-row{display:flex;align-items:baseline;justify-content:space-between}\n"]
1840
+ styles: [":host ::ng-deep trix-toolbar{top:24px}.facets{margin-top:12px;display:flex;flex-wrap:wrap;align-items:center}@media screen and (min-width: 768px){.facets{max-width:340px}}vdr-action-bar clr-toggle-wrapper{margin-top:12px}.variant-filter{flex:1;display:flex}.variant-filter input{flex:1;max-width:initial;border-radius:3px 0 0 3px!important}.variant-filter .icon-button{border:1px solid var(--color-component-border-300);background-color:var(--color-component-bg-100);border-radius:0 3px 3px 0;border-left:none}.group-name{padding-right:6px}.view-mode{display:flex;justify-content:flex-end;align-items:center}.edit-variants-btn{margin-top:0}.channel-assignment{flex-wrap:wrap;max-height:144px;overflow-y:auto}.auto-rename-wrapper{overflow:hidden;max-height:0;padding-left:9.5rem;margin-bottom:0;transition:max-height .2s,margin-bottom .2s}.auto-rename-wrapper.visible{max-height:24px;margin-bottom:12px}.pagination-row{display:flex;align-items:baseline;justify-content:space-between}\n"]
1778
1841
  },] }
1779
1842
  ];
1780
1843
  ProductDetailComponent.ctorParameters = () => [
@@ -1920,8 +1983,8 @@ class ProductListComponent extends BaseListComponent {
1920
1983
  ProductListComponent.decorators = [
1921
1984
  { type: Component, args: [{
1922
1985
  selector: 'vdr-products-list',
1923
- template: "<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"> </vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"> </vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: { count: pendingSearchIndexUpdates }\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-checkbox-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\" />\r\n <label>{{ 'catalog.group-by-product' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.create-new-product' | translate }}</span>\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n {{ groupByProduct ? result.productName : result.productVariantName }}\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></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)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\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 </ng-template>\r\n</vdr-data-table>\r\n",
1924
- styles: [".image-placeholder{width:50px;height:50px;background-color:var(--color-component-bg-200)}.image-placeholder .placeholder{text-align:center;color:var(--color-grey-300)}.search-form{display:flex;align-items:center;width:100%;margin-bottom:6px}.search-input{min-width:300px}@media screen and (max-width: 768px){.search-input{min-width:100px}}.search-settings-menu{margin:0 12px}td.disabled{background-color:var(--color-component-bg-200)}.search-index-button{position:relative}.search-index-button vdr-status-badge{right:0;top:0}.run-updates-button{position:relative}.run-updates-button vdr-status-badge{left:10px;top:10px}\n"]
1986
+ template: "<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"></vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"></vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: {count: pendingSearchIndexUpdates}\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-checkbox-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\"/>\r\n <label>{{ 'catalog.group-by-product' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.create-new-product' | translate }}</span>\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle image-col\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n {{ groupByProduct ? result.productName : result.productVariantName }}\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n class=\"edit-button\"\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></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)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\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 </ng-template>\r\n</vdr-data-table>\r\n",
1987
+ styles: [".image-col{width:70px}.image-placeholder{width:50px;height:50px;background-color:var(--color-component-bg-200)}.image-placeholder img{border-radius:var(--border-radius-img)}.image-placeholder .placeholder{text-align:center;color:var(--color-grey-300)}.search-form{display:flex;align-items:center;width:100%;margin-bottom:6px}.search-input{min-width:300px}@media screen and (max-width: 768px){.search-input{min-width:100px}}.search-settings-menu{margin:0 12px}td.disabled{background-color:var(--color-component-bg-200)}.search-index-button{position:relative}.search-index-button vdr-status-badge{right:0;top:0}.run-updates-button{position:relative}.run-updates-button vdr-status-badge{left:10px;top:10px}.edit-button{margin-right:24px}\n"]
1925
1988
  },] }
1926
1989
  ];
1927
1990
  ProductListComponent.ctorParameters = () => [
@@ -2559,7 +2622,7 @@ ProductVariantsResolver.ctorParameters = () => [
2559
2622
  { type: DataService }
2560
2623
  ];
2561
2624
 
2562
- const ɵ0$1 = {
2625
+ const ɵ0 = {
2563
2626
  breadcrumb: marker('breadcrumb.products'),
2564
2627
  }, ɵ1 = {
2565
2628
  breadcrumb: productBreadcrumb,
@@ -2584,7 +2647,7 @@ const catalogRoutes = [
2584
2647
  {
2585
2648
  path: 'products',
2586
2649
  component: ProductListComponent,
2587
- data: ɵ0$1,
2650
+ data: ɵ0,
2588
2651
  },
2589
2652
  {
2590
2653
  path: 'products/:id',
@@ -2790,7 +2853,7 @@ AssetsComponent.decorators = [
2790
2853
  selector: 'vdr-assets',
2791
2854
  template: "<div class=\"card\" *ngIf=\"!compact; else compactView\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'small'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"image\" size=\"128\"></clr-icon>\r\n <div>{{ 'catalog.no-featured-asset' | translate }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\"><ng-container *ngTemplateOutlet=\"assetList\"></ng-container></div>\r\n <div class=\"card-footer\" *vdrIfPermissions=\"updatePermissions\">\r\n <button class=\"btn\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #compactView>\r\n <div class=\"featured-asset compact\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'thumb'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\"><clr-icon shape=\"image\" size=\"150\"></clr-icon></div>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"assetList\"></ng-container>\r\n <button\r\n *vdrIfPermissions=\"updatePermissions\"\r\n class=\"compact-select btn btn-icon btn-sm btn-block\"\r\n [title]=\"'asset.add-asset' | translate\"\r\n (click)=\"selectAssets()\"\r\n >\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n</ng-template>\r\n\r\n<ng-template #assetList>\r\n <div class=\"all-assets\" [class.compact]=\"compact\" cdkDropListGroup>\r\n <div\r\n *ngFor=\"let asset of assets; let index = index\"\r\n class=\"drop-list\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"index\"\r\n [cdkDropListDisabled]=\"!(updatePermissions | hasPermission)\"\r\n (cdkDropListDropped)=\"dropListDropped($event)\"\r\n >\r\n <vdr-dropdown cdkDrag>\r\n <div\r\n class=\"asset-thumb\"\r\n vdrDropdownTrigger\r\n [class.featured]=\"isFeatured(asset)\"\r\n [title]=\"\"\r\n tabindex=\"0\"\r\n >\r\n <img [src]=\"asset | assetPreview:'tiny'\" />\r\n </div>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button type=\"button\" vdrDropdownItem (click)=\"previewAsset(asset)\">\r\n {{ 'asset.preview' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n [disabled]=\"isFeatured(asset) || !(updatePermissions | hasPermission)\"\r\n vdrDropdownItem\r\n (click)=\"setAsFeatured(asset)\"\r\n >\r\n {{ 'asset.set-as-featured-asset' | translate }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n class=\"remove-asset\"\r\n vdrDropdownItem\r\n [disabled]=\"!(updatePermissions | hasPermission)\"\r\n (click)=\"removeAsset(asset)\"\r\n >\r\n {{ 'asset.remove-asset' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n</ng-template>\r\n",
2792
2855
  changeDetection: ChangeDetectionStrategy.OnPush,
2793
- styles: [":host{width:340px;display:block}:host.compact{width:162px}.placeholder{text-align:center;color:var(--color-grey-300)}.featured-asset{text-align:center;background:var(--color-component-bg-200);padding:6px;cursor:pointer}.featured-asset.compact{width:100%;min-height:40px;position:relative;padding:6px}.featured-asset .compact-select{position:absolute;bottom:6px;right:6px;margin:0}.all-assets{display:flex;flex-wrap:wrap}.all-assets .drop-list{min-width:60px}.all-assets .asset-thumb{margin:3px;padding:0;border:2px solid var(--color-component-border-100);cursor:pointer}.all-assets .asset-thumb img{width:50px;height:50px}.all-assets .asset-thumb.featured{border-color:var(--color-primary-500)}.all-assets .remove-asset{color:var(--color-warning-500)}.all-assets.compact .drop-list{min-width:54px}.all-assets.compact .asset-thumb{margin:1px;border-width:1px}.all-assets.compact .cdk-drag-placeholder{width:50px}.all-assets.compact .cdk-drag-placeholder .asset-thumb{width:50px}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.example-box:last-child{border:none}.all-assets.cdk-drop-list-dragging vdr-dropdown:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging>*:not(.cdk-drag-placeholder){display:none}\n"]
2856
+ styles: [":host{width:340px;display:block}:host.compact{width:162px}.placeholder{text-align:center;color:var(--color-grey-300)}.featured-asset{text-align:center;background:var(--color-component-bg-200);padding:6px;cursor:pointer;border-radius:var(--border-radius-img)}.featured-asset img{border-radius:var(--border-radius-img)}.featured-asset.compact{width:100%;min-height:40px;position:relative;padding:6px}.featured-asset .compact-select{position:absolute;bottom:6px;right:6px;margin:0}.all-assets{display:flex;flex-wrap:wrap}.all-assets .drop-list{min-width:60px}.all-assets .asset-thumb{margin:3px;padding:0;border:2px solid var(--color-component-border-100);border-radius:var(--border-radius-img);cursor:pointer}.all-assets .asset-thumb img{width:50px;height:50px;border-radius:var(--border-radius-img)}.all-assets .asset-thumb.featured{border-color:var(--color-primary-500);border-radius:calc(var(--border-radius-img) + 2px)}.all-assets .remove-asset{color:var(--color-warning-500)}.all-assets.compact .drop-list{min-width:54px}.all-assets.compact .asset-thumb{margin:1px;border-width:1px}.all-assets.compact .cdk-drag-placeholder{width:50px}.all-assets.compact .cdk-drag-placeholder .asset-thumb{width:50px}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.example-box:last-child{border:none}.all-assets.cdk-drop-list-dragging vdr-dropdown:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drop-list-dragging>*:not(.cdk-drag-placeholder){display:none}\n"]
2794
2857
  },] }
2795
2858
  ];
2796
2859
  AssetsComponent.ctorParameters = () => [
@@ -2810,34 +2873,64 @@ class CollectionContentsComponent {
2810
2873
  this.route = route;
2811
2874
  this.router = router;
2812
2875
  this.dataService = dataService;
2876
+ this.previewUpdatedFilters = false;
2813
2877
  this.filterTermControl = new FormControl('');
2878
+ this.isLoading = false;
2814
2879
  this.collectionIdChange$ = new BehaviorSubject('');
2880
+ this.parentIdChange$ = new BehaviorSubject('');
2881
+ this.filterChanges$ = new BehaviorSubject([]);
2815
2882
  this.refresh$ = new BehaviorSubject(true);
2816
2883
  this.destroy$ = new Subject();
2817
2884
  }
2818
2885
  ngOnInit() {
2819
- this.contentsCurrentPage$ = this.route.paramMap.pipe(map(qpm => qpm.get('contentsPage')), map(page => (!page ? 1 : +page)), startWith(1), distinctUntilChanged());
2820
- this.contentsItemsPerPage$ = this.route.paramMap.pipe(map(qpm => qpm.get('contentsPerPage')), map(perPage => (!perPage ? 10 : +perPage)), startWith(10), distinctUntilChanged());
2886
+ this.contentsCurrentPage$ = this.route.queryParamMap.pipe(map(qpm => qpm.get('contentsPage')), map(page => (!page ? 1 : +page)), startWith(1), distinctUntilChanged());
2887
+ this.contentsItemsPerPage$ = this.route.queryParamMap.pipe(map(qpm => qpm.get('contentsPerPage')), map(perPage => (!perPage ? 10 : +perPage)), startWith(10), distinctUntilChanged());
2821
2888
  const filterTerm$ = this.filterTermControl.valueChanges.pipe(debounceTime(250), tap(() => this.setContentsPageNumber(1)), startWith(''));
2822
- const collection$ = combineLatest(this.collectionIdChange$, this.contentsCurrentPage$, this.contentsItemsPerPage$, filterTerm$, this.refresh$).pipe(takeUntil(this.destroy$), switchMap(([id, currentPage, itemsPerPage, filterTerm]) => {
2889
+ const filterChanges$ = this.filterChanges$.asObservable().pipe(filter(() => this.previewUpdatedFilters), tap(() => this.setContentsPageNumber(1)), startWith([]));
2890
+ const fetchUpdate$ = combineLatest(this.collectionIdChange$, this.parentIdChange$, this.contentsCurrentPage$, this.contentsItemsPerPage$, filterTerm$, filterChanges$, this.refresh$);
2891
+ const collection$ = fetchUpdate$.pipe(takeUntil(this.destroy$), tap(() => (this.isLoading = true)), debounceTime(50), switchMap(([id, parentId, currentPage, itemsPerPage, filterTerm, filters]) => {
2823
2892
  const take = itemsPerPage;
2824
2893
  const skip = (currentPage - 1) * itemsPerPage;
2825
- if (id) {
2894
+ if (filters.length && this.previewUpdatedFilters) {
2895
+ const filterClause = filterTerm
2896
+ ? { name: { contains: filterTerm } }
2897
+ : undefined;
2898
+ return this.dataService.collection
2899
+ .previewCollectionVariants({
2900
+ parentId,
2901
+ filters,
2902
+ }, {
2903
+ take,
2904
+ skip,
2905
+ filter: filterClause,
2906
+ })
2907
+ .mapSingle(data => data.previewCollectionVariants)
2908
+ .pipe(catchError(() => of({ items: [], totalItems: 0 })));
2909
+ }
2910
+ else if (id) {
2826
2911
  return this.dataService.collection
2827
2912
  .getCollectionContents(id, take, skip, filterTerm)
2828
- .mapSingle(data => data.collection);
2913
+ .mapSingle(data => { var _a; return (_a = data.collection) === null || _a === void 0 ? void 0 : _a.productVariants; });
2829
2914
  }
2830
2915
  else {
2831
2916
  return of(null);
2832
2917
  }
2833
- }));
2834
- this.contents$ = collection$.pipe(map(result => (result ? result.productVariants.items : [])));
2835
- this.contentsTotalItems$ = collection$.pipe(map(result => (result ? result.productVariants.totalItems : 0)));
2918
+ }), tap(() => (this.isLoading = false)), finalize(() => (this.isLoading = false)));
2919
+ this.contents$ = collection$.pipe(map(result => (result ? result.items : [])));
2920
+ this.contentsTotalItems$ = collection$.pipe(map(result => (result ? result.totalItems : 0)));
2836
2921
  }
2837
2922
  ngOnChanges(changes) {
2838
2923
  if ('collectionId' in changes) {
2839
2924
  this.collectionIdChange$.next(changes.collectionId.currentValue);
2840
2925
  }
2926
+ if ('parentId' in changes) {
2927
+ this.parentIdChange$.next(changes.parentId.currentValue);
2928
+ }
2929
+ if ('updatedFilters' in changes) {
2930
+ if (this.updatedFilters) {
2931
+ this.filterChanges$.next(this.updatedFilters);
2932
+ }
2933
+ }
2841
2934
  }
2842
2935
  ngOnDestroy() {
2843
2936
  this.destroy$.next();
@@ -2853,18 +2946,22 @@ class CollectionContentsComponent {
2853
2946
  this.refresh$.next(true);
2854
2947
  }
2855
2948
  setParam(key, value) {
2856
- this.router.navigate(['./', Object.assign(Object.assign({}, this.route.snapshot.params), { [key]: value })], {
2949
+ this.router.navigate(['./'], {
2857
2950
  relativeTo: this.route,
2951
+ queryParams: {
2952
+ [key]: value,
2953
+ },
2858
2954
  queryParamsHandling: 'merge',
2955
+ replaceUrl: true,
2859
2956
  });
2860
2957
  }
2861
2958
  }
2862
2959
  CollectionContentsComponent.decorators = [
2863
2960
  { type: Component, args: [{
2864
2961
  selector: 'vdr-collection-contents',
2865
- template: "<div class=\"contents-header\">\r\n <div class=\"header-title-row\">\r\n <ng-container\r\n *ngTemplateOutlet=\"headerTemplate; context: { $implicit: contentsTotalItems$ | async }\"\r\n ></ng-container>\r\n </div>\r\n <input\r\n type=\"text\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n [formControl]=\"filterTermControl\"\r\n />\r\n</div>\r\n<vdr-data-table\r\n [items]=\"contents$ | async\"\r\n [itemsPerPage]=\"contentsItemsPerPage$ | async\"\r\n [totalItems]=\"contentsTotalItems$ | async\"\r\n [currentPage]=\"contentsCurrentPage$ | async\"\r\n (pageChange)=\"setContentsPageNumber($event)\"\r\n (itemsPerPageChange)=\"setContentsItemsPerPage($event)\"\r\n>\r\n <ng-template let-variant=\"item\">\r\n <td class=\"left align-middle\">{{ variant.name }}</td>\r\n <td class=\"right align-middle\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['/catalog/products', variant.productId, { tab: 'variants' }]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n",
2962
+ template: "<div class=\"contents-header\">\r\n <div class=\"header-title-row\">\r\n <ng-container\r\n *ngTemplateOutlet=\"headerTemplate; context: { $implicit: contentsTotalItems$ | async }\"\r\n ></ng-container>\r\n </div>\r\n <input\r\n type=\"text\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n [formControl]=\"filterTermControl\"\r\n />\r\n</div>\r\n<div class=\"table-wrapper\">\r\n <div class=\"progress loop\" [class.visible]=\"isLoading\"></div>\r\n <vdr-data-table\r\n [class.loading]=\"isLoading\"\r\n [items]=\"contents$ | async\"\r\n [itemsPerPage]=\"contentsItemsPerPage$ | async\"\r\n [totalItems]=\"contentsTotalItems$ | async\"\r\n [currentPage]=\"contentsCurrentPage$ | async\"\r\n (pageChange)=\"setContentsPageNumber($event)\"\r\n (itemsPerPageChange)=\"setContentsItemsPerPage($event)\"\r\n >\r\n <ng-template let-variant=\"item\">\r\n <td class=\"left align-middle\">{{ variant.name }}</td>\r\n <td class=\"left align-middle\"><small class=\"sku\">{{ variant.sku }}</small></td>\r\n <td class=\"right align-middle\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['/catalog/products', variant.productId, { tab: 'variants' }]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n </ng-template>\r\n </vdr-data-table>\r\n</div>\r\n",
2866
2963
  changeDetection: ChangeDetectionStrategy.OnPush,
2867
- styles: [".contents-header{background-color:var(--color-component-bg-100);position:sticky;top:0;padding:6px;z-index:1;border-bottom:1px solid var(--color-component-border-200)}.contents-header .header-title-row{display:flex;justify-content:space-between;align-items:center}.contents-header .clr-input{width:100%}:host ::ng-deep table{margin-top:-1px}\n"]
2964
+ styles: [".contents-header{background-color:var(--color-component-bg-100);position:sticky;top:0;padding:6px;z-index:1;border-bottom:1px solid var(--color-component-border-200)}.contents-header .header-title-row{display:flex;justify-content:space-between;align-items:center}.contents-header .clr-input{width:100%}:host{display:block}:host ::ng-deep table{margin-top:-1px}vdr-data-table{opacity:1;transition:opacity .3s}vdr-data-table.loading{opacity:.5}.table-wrapper{position:relative}.progress{position:absolute;top:0;left:0;overflow:hidden;height:6px;opacity:0;transition:opacity .1s}.progress.visible{opacity:1}.sku{color:var(--color-text-200)}\n"]
2868
2965
  },] }
2869
2966
  ];
2870
2967
  CollectionContentsComponent.ctorParameters = () => [
@@ -2874,6 +2971,9 @@ CollectionContentsComponent.ctorParameters = () => [
2874
2971
  ];
2875
2972
  CollectionContentsComponent.propDecorators = {
2876
2973
  collectionId: [{ type: Input }],
2974
+ parentId: [{ type: Input }],
2975
+ updatedFilters: [{ type: Input }],
2976
+ previewUpdatedFilters: [{ type: Input }],
2877
2977
  headerTemplate: [{ type: ContentChild, args: [TemplateRef, { static: true },] }]
2878
2978
  };
2879
2979
 
@@ -2881,7 +2981,7 @@ CollectionContentsComponent.propDecorators = {
2881
2981
  * Builds a tree from an array of nodes which have a parent.
2882
2982
  * Based on https://stackoverflow.com/a/31247960/772859, modified to preserve ordering.
2883
2983
  */
2884
- function arrayToTree(nodes, currentState) {
2984
+ function arrayToTree(nodes, currentState, expandedIds = []) {
2885
2985
  var _a, _b;
2886
2986
  const topLevelNodes = [];
2887
2987
  const mappedArr = {};
@@ -2893,7 +2993,7 @@ function arrayToTree(nodes, currentState) {
2893
2993
  for (const id of nodes.map(n => n.id)) {
2894
2994
  if (mappedArr.hasOwnProperty(id)) {
2895
2995
  const mappedElem = mappedArr[id];
2896
- mappedElem.expanded = (_b = (_a = currentStateMap.get(id)) === null || _a === void 0 ? void 0 : _a.expanded) !== null && _b !== void 0 ? _b : false;
2996
+ mappedElem.expanded = (_b = (_a = currentStateMap.get(id)) === null || _a === void 0 ? void 0 : _a.expanded) !== null && _b !== void 0 ? _b : expandedIds.includes(id);
2897
2997
  const parent = mappedElem.parent;
2898
2998
  if (!parent) {
2899
2999
  continue;
@@ -2937,13 +3037,14 @@ function treeToMap(tree) {
2937
3037
  class CollectionTreeComponent {
2938
3038
  constructor() {
2939
3039
  this.expandAll = false;
3040
+ this.expandedIds = [];
2940
3041
  this.rearrange = new EventEmitter();
2941
3042
  this.deleteCollection = new EventEmitter();
2942
3043
  this.allMoveListItems = [];
2943
3044
  }
2944
3045
  ngOnChanges(changes) {
2945
3046
  if ('collections' in changes && this.collections) {
2946
- this.collectionTree = arrayToTree(this.collections, this.collectionTree);
3047
+ this.collectionTree = arrayToTree(this.collections, this.collectionTree, this.expandedIds);
2947
3048
  this.allMoveListItems = [];
2948
3049
  }
2949
3050
  }
@@ -3002,15 +3103,18 @@ CollectionTreeComponent.propDecorators = {
3002
3103
  collections: [{ type: Input }],
3003
3104
  activeCollectionId: [{ type: Input }],
3004
3105
  expandAll: [{ type: Input }],
3106
+ expandedIds: [{ type: Input }],
3005
3107
  rearrange: [{ type: Output }],
3006
3108
  deleteCollection: [{ type: Output }]
3007
3109
  };
3008
3110
 
3009
3111
  class CollectionTreeNodeComponent {
3010
- constructor(parent, root, dataService) {
3112
+ constructor(parent, root, dataService, router, route) {
3011
3113
  this.parent = parent;
3012
3114
  this.root = root;
3013
3115
  this.dataService = dataService;
3116
+ this.router = router;
3117
+ this.route = route;
3014
3118
  this.depth = 0;
3015
3119
  this.expandAll = false;
3016
3120
  this.moveListItems = [];
@@ -3038,6 +3142,24 @@ class CollectionTreeNodeComponent {
3038
3142
  trackByFn(index, item) {
3039
3143
  return item.id;
3040
3144
  }
3145
+ toggleExpanded(collection) {
3146
+ var _a, _b;
3147
+ collection.expanded = !collection.expanded;
3148
+ let expandedIds = (_b = (_a = this.route.snapshot.queryParamMap.get('expanded')) === null || _a === void 0 ? void 0 : _a.split(',')) !== null && _b !== void 0 ? _b : [];
3149
+ if (collection.expanded) {
3150
+ expandedIds.push(collection.id);
3151
+ }
3152
+ else {
3153
+ expandedIds = expandedIds.filter(id => id !== collection.id);
3154
+ }
3155
+ this.router.navigate(['./'], {
3156
+ queryParams: {
3157
+ expanded: expandedIds.filter(id => !!id).join(','),
3158
+ },
3159
+ queryParamsHandling: 'merge',
3160
+ relativeTo: this.route,
3161
+ });
3162
+ }
3041
3163
  getMoveListItems(collection) {
3042
3164
  this.moveListItems = this.root.getMoveListItems(collection);
3043
3165
  }
@@ -3079,7 +3201,7 @@ class CollectionTreeNodeComponent {
3079
3201
  CollectionTreeNodeComponent.decorators = [
3080
3202
  { type: Component, args: [{
3081
3203
  selector: 'vdr-collection-tree-node',
3082
- template: "<div\r\n cdkDropList\r\n class=\"tree-node\"\r\n #dropList\r\n [cdkDropListData]=\"collectionTree\"\r\n [cdkDropListDisabled]=\"!(hasUpdatePermission$ | async)\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n>\r\n <div\r\n class=\"collection\"\r\n [class.private]=\"collection.isPrivate\"\r\n *ngFor=\"let collection of collectionTree.children; index as i; trackBy: trackByFn\"\r\n cdkDrag\r\n [cdkDragData]=\"collection\"\r\n >\r\n <div\r\n class=\"collection-detail\"\r\n [ngClass]=\"'depth-' + depth\"\r\n [class.active]=\"collection.id === activeCollectionId\"\r\n >\r\n <div class=\"name\">\r\n <button\r\n class=\"icon-button folder-button\"\r\n [disabled]=\"expandAll\"\r\n *ngIf=\"collection.children?.length; else folderSpacer\"\r\n (click)=\"collection.expanded = !collection.expanded\"\r\n >\r\n <clr-icon shape=\"folder\" *ngIf=\"!collection.expanded && !expandAll\"></clr-icon>\r\n <clr-icon shape=\"folder-open\" *ngIf=\"collection.expanded || expandAll\"></clr-icon>\r\n </button>\r\n <ng-template #folderSpacer>\r\n <div class=\"folder-button-spacer\"></div>\r\n </ng-template>\r\n {{ collection.name }}\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <vdr-chip *ngIf=\"collection.isPrivate\">{{ 'catalog.private' | translate }}</vdr-chip>\r\n <a\r\n class=\"btn btn-link btn-sm\"\r\n [routerLink]=\"['./', { contents: collection.id }]\"\r\n queryParamsHandling=\"preserve\"\r\n >\r\n <clr-icon shape=\"view-list\"></clr-icon>\r\n {{ 'catalog.view-contents' | translate }}\r\n </a>\r\n <a class=\"btn btn-link btn-sm\" [routerLink]=\"['/catalog/collections/', collection.id]\">\r\n <clr-icon shape=\"edit\"></clr-icon>\r\n {{ 'common.edit' | translate }}\r\n </a>\r\n <div class=\"drag-handle\" cdkDragHandle *vdrIfPermissions=\"['UpdateCatalog', 'UpdateCollection']\">\r\n <clr-icon shape=\"drag-handle\" size=\"24\"></clr-icon>\r\n </div>\r\n <vdr-dropdown>\r\n <button class=\"icon-button\" vdrDropdownTrigger (click)=\"getMoveListItems(collection)\">\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <a\r\n class=\"dropdown-item\"\r\n [routerLink]=\"['./', 'create', { parentId: collection.id }]\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"i === 0 || !(hasUpdatePermission$ | async)\"\r\n (click)=\"moveUp(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret up\"></clr-icon>\r\n {{ 'catalog.move-up' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"\r\n i === collectionTree.children.length - 1 || !(hasUpdatePermission$ | async)\r\n \"\r\n (click)=\"moveDown(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n {{ 'catalog.move-down' | translate }}\r\n </button>\r\n <h4 class=\"dropdown-header\">{{ 'catalog.move-to' | translate }}</h4>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n *ngFor=\"let item of moveListItems\"\r\n (click)=\"move(collection, item.id)\"\r\n [disabled]=\"!(hasUpdatePermission$ | async)\"\r\n >\r\n <div class=\"move-to-item\">\r\n <div class=\"move-icon\">\r\n <clr-icon shape=\"child-arrow\"></clr-icon>\r\n </div>\r\n <div class=\"path\">\r\n {{ item.path }}\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n class=\"button\"\r\n vdrDropdownItem\r\n (click)=\"delete(collection.id)\"\r\n [disabled]=\"!(hasDeletePermission$ | async)\"\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 </div>\r\n <vdr-collection-tree-node\r\n *ngIf=\"collection.expanded || expandAll\"\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collection\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n ></vdr-collection-tree-node>\r\n </div>\r\n</div>\r\n",
3204
+ template: "<div\r\n cdkDropList\r\n class=\"tree-node\"\r\n #dropList\r\n [cdkDropListData]=\"collectionTree\"\r\n [cdkDropListDisabled]=\"!(hasUpdatePermission$ | async)\"\r\n (cdkDropListDropped)=\"drop($event)\"\r\n>\r\n <div\r\n class=\"collection\"\r\n [class.private]=\"collection.isPrivate\"\r\n *ngFor=\"let collection of collectionTree.children; index as i; trackBy: trackByFn\"\r\n cdkDrag\r\n [cdkDragData]=\"collection\"\r\n >\r\n <div\r\n class=\"collection-detail\"\r\n [ngClass]=\"'depth-' + depth\"\r\n [class.active]=\"collection.id === activeCollectionId\"\r\n >\r\n <div class=\"name\">\r\n <button\r\n class=\"icon-button folder-button\"\r\n [disabled]=\"expandAll\"\r\n *ngIf=\"collection.children?.length; else folderSpacer\"\r\n (click)=\"toggleExpanded(collection)\"\r\n >\r\n <clr-icon shape=\"folder\" *ngIf=\"!collection.expanded && !expandAll\"></clr-icon>\r\n <clr-icon shape=\"folder-open\" *ngIf=\"collection.expanded || expandAll\"></clr-icon>\r\n </button>\r\n <ng-template #folderSpacer>\r\n <div class=\"folder-button-spacer\"></div>\r\n </ng-template>\r\n {{ collection.name }}\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <vdr-chip *ngIf=\"collection.isPrivate\">{{ 'catalog.private' | translate }}</vdr-chip>\r\n <a\r\n class=\"btn btn-link btn-sm\"\r\n [routerLink]=\"['./', { contents: collection.id }]\"\r\n queryParamsHandling=\"preserve\"\r\n >\r\n <clr-icon shape=\"view-list\"></clr-icon>\r\n {{ 'catalog.view-contents' | translate }}\r\n </a>\r\n <a class=\"btn btn-link btn-sm\" [routerLink]=\"['/catalog/collections/', collection.id]\">\r\n <clr-icon shape=\"edit\"></clr-icon>\r\n {{ 'common.edit' | translate }}\r\n </a>\r\n <div class=\"drag-handle\" cdkDragHandle *vdrIfPermissions=\"['UpdateCatalog', 'UpdateCollection']\">\r\n <clr-icon shape=\"drag-handle\" size=\"24\"></clr-icon>\r\n </div>\r\n <vdr-dropdown>\r\n <button class=\"icon-button\" vdrDropdownTrigger (click)=\"getMoveListItems(collection)\">\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <a\r\n class=\"dropdown-item\"\r\n [routerLink]=\"['./', 'create', { parentId: collection.id }]\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"i === 0 || !(hasUpdatePermission$ | async)\"\r\n (click)=\"moveUp(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret up\"></clr-icon>\r\n {{ 'catalog.move-up' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"\r\n i === collectionTree.children.length - 1 || !(hasUpdatePermission$ | async)\r\n \"\r\n (click)=\"moveDown(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n {{ 'catalog.move-down' | translate }}\r\n </button>\r\n <h4 class=\"dropdown-header\">{{ 'catalog.move-to' | translate }}</h4>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n *ngFor=\"let item of moveListItems\"\r\n (click)=\"move(collection, item.id)\"\r\n [disabled]=\"!(hasUpdatePermission$ | async)\"\r\n >\r\n <div class=\"move-to-item\">\r\n <div class=\"move-icon\">\r\n <clr-icon shape=\"child-arrow\"></clr-icon>\r\n </div>\r\n <div class=\"path\">\r\n {{ item.path }}\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n class=\"button\"\r\n vdrDropdownItem\r\n (click)=\"delete(collection.id)\"\r\n [disabled]=\"!(hasDeletePermission$ | async)\"\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 </div>\r\n <vdr-collection-tree-node\r\n *ngIf=\"collection.expanded || expandAll\"\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collection\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n ></vdr-collection-tree-node>\r\n </div>\r\n</div>\r\n",
3083
3205
  changeDetection: ChangeDetectionStrategy.OnPush,
3084
3206
  styles: [":host{display:block}.collection{background-color:var(--color-component-bg-100);font-size:.65rem;transition:transform .25s cubic-bezier(0,0,.2,1);margin-bottom:2px;border-left:2px solid transparent;transition:border-left-color .2s}.collection.private{background-color:var(--color-component-bg-200)}.collection .collection-detail{padding:6px 12px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--color-component-border-100)}.collection .collection-detail.active{background-color:var(--clr-global-selection-color)}.collection .collection-detail.depth-1{padding-left:36px}.collection .collection-detail.depth-2{padding-left:60px}.collection .collection-detail.depth-3{padding-left:84px}.collection .collection-detail.depth-4{padding-left:108px}.collection .collection-detail .folder-button-spacer{display:inline-block;width:28px}.tree-node{display:block;background:var(--color-component-bg-100);overflow:hidden}.tree-node.cdk-drop-list-dragging>.collection{border-left-color:var(--color-primary-300)}.drag-placeholder{min-height:120px;background-color:var(--color-component-bg-300);transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-preview{box-sizing:border-box;border-radius:4px;box-shadow:0 5px 5px -3px #0003,0 8px 10px 1px #00000024,0 3px 14px 2px #0000001f}.cdk-drag-placeholder{opacity:0}.cdk-drag-animating{transition:transform .25s cubic-bezier(0,0,.2,1)}.example-list.cdk-drop-list-dragging .tree-node:not(.cdk-drag-placeholder){transition:transform .25s cubic-bezier(0,0,.2,1)}.move-to-item{display:flex;white-space:normal;align-items:baseline}.move-to-item .move-icon{flex:none;margin-right:3px}.move-to-item .path{line-height:18px}\n"]
3085
3207
  },] }
@@ -3087,7 +3209,9 @@ CollectionTreeNodeComponent.decorators = [
3087
3209
  CollectionTreeNodeComponent.ctorParameters = () => [
3088
3210
  { type: CollectionTreeNodeComponent, decorators: [{ type: SkipSelf }, { type: Optional }] },
3089
3211
  { type: CollectionTreeComponent },
3090
- { type: DataService }
3212
+ { type: DataService },
3213
+ { type: Router },
3214
+ { type: ActivatedRoute }
3091
3215
  ];
3092
3216
  CollectionTreeNodeComponent.propDecorators = {
3093
3217
  collectionTree: [{ type: Input }],
@@ -3265,105 +3389,6 @@ OptionValueInputComponent.propDecorators = {
3265
3389
  textArea: [{ type: ViewChild, args: ['textArea', { static: true },] }]
3266
3390
  };
3267
3391
 
3268
- const ɵ0 = SingleSearchSelectionModelFactory;
3269
- class ProductSearchInputComponent {
3270
- constructor() {
3271
- this.searchTermChange = new EventEmitter();
3272
- this.facetValueChange = new EventEmitter();
3273
- this.lastTerm = '';
3274
- this.lastFacetValueIds = [];
3275
- this.filterFacetResults = (term, item) => {
3276
- if (!this.isFacetValueItem(item)) {
3277
- return false;
3278
- }
3279
- const cix = term.indexOf(':');
3280
- const facetName = cix > -1 ? term.toLowerCase().slice(0, cix) : null;
3281
- const facetVal = cix > -1 ? term.toLowerCase().slice(cix + 1) : term.toLowerCase();
3282
- if (facetName) {
3283
- return (item.facetValue.facet.name.toLowerCase().includes(facetName) &&
3284
- item.facetValue.name.toLocaleLowerCase().includes(facetVal));
3285
- }
3286
- return (item.facetValue.name.toLowerCase().includes(term.toLowerCase()) ||
3287
- item.facetValue.facet.name.toLowerCase().includes(term.toLowerCase()));
3288
- };
3289
- this.isFacetValueItem = (input) => {
3290
- return typeof input === 'object' && !!input && input.hasOwnProperty('facetValue');
3291
- };
3292
- }
3293
- setSearchTerm(term) {
3294
- if (term) {
3295
- this.selectComponent.select({ label: term, value: { label: term } });
3296
- }
3297
- else {
3298
- const currentTerm = this.selectComponent.selectedItems.find(i => !this.isFacetValueItem(i.value));
3299
- if (currentTerm) {
3300
- this.selectComponent.unselect(currentTerm);
3301
- }
3302
- }
3303
- }
3304
- setFacetValues(ids) {
3305
- const items = this.selectComponent.items;
3306
- this.selectComponent.selectedItems.forEach(item => {
3307
- if (this.isFacetValueItem(item.value) && !ids.includes(item.value.facetValue.id)) {
3308
- this.selectComponent.unselect(item);
3309
- }
3310
- });
3311
- ids.map(id => {
3312
- return items === null || items === void 0 ? void 0 : items.find(item => this.isFacetValueItem(item) && item.facetValue.id === id);
3313
- })
3314
- .filter(notNullOrUndefined)
3315
- .forEach(item => {
3316
- const isSelected = this.selectComponent.selectedItems.find(i => {
3317
- const val = i.value;
3318
- if (this.isFacetValueItem(val)) {
3319
- return val.facetValue.id === item.facetValue.id;
3320
- }
3321
- return false;
3322
- });
3323
- if (!isSelected) {
3324
- this.selectComponent.select({ label: '', value: item });
3325
- }
3326
- });
3327
- }
3328
- onSelectChange(selectedItems) {
3329
- if (!Array.isArray(selectedItems)) {
3330
- selectedItems = [selectedItems];
3331
- }
3332
- const searchTermItem = selectedItems.find(item => !this.isFacetValueItem(item));
3333
- const searchTerm = searchTermItem ? searchTermItem.label : '';
3334
- const facetValueIds = selectedItems.filter(this.isFacetValueItem).map(i => i.facetValue.id);
3335
- if (searchTerm !== this.lastTerm) {
3336
- this.searchTermChange.emit(searchTerm);
3337
- this.lastTerm = searchTerm;
3338
- }
3339
- if (this.lastFacetValueIds.join(',') !== facetValueIds.join(',')) {
3340
- this.facetValueChange.emit(facetValueIds);
3341
- this.lastFacetValueIds = facetValueIds;
3342
- }
3343
- }
3344
- addTagFn(item) {
3345
- return { label: item };
3346
- }
3347
- isSearchHeaderSelected() {
3348
- return this.selectComponent.itemsList.markedIndex === -1;
3349
- }
3350
- }
3351
- ProductSearchInputComponent.decorators = [
3352
- { type: Component, args: [{
3353
- selector: 'vdr-product-search-input',
3354
- template: "<ng-select\r\n [addTag]=\"addTagFn\"\r\n [placeholder]=\"'catalog.search-product-name-or-code' | translate\"\r\n [items]=\"facetValueResults\"\r\n [searchFn]=\"filterFacetResults\"\r\n [hideSelected]=\"true\"\r\n [multiple]=\"true\"\r\n [markFirst]=\"false\"\r\n (change)=\"onSelectChange($event)\"\r\n #selectComponent\r\n>\r\n <ng-template ng-header-tmp>\r\n <div\r\n class=\"search-header\"\r\n *ngIf=\"selectComponent.searchTerm\"\r\n [class.selected]=\"isSearchHeaderSelected()\"\r\n (click)=\"selectComponent.selectTag()\"\r\n >\r\n {{ 'catalog.search-for-term' | translate }}: {{ selectComponent.searchTerm }}\r\n </div>\r\n </ng-template>\r\n <ng-template ng-label-tmp let-item=\"item\" let-clear=\"clear\">\r\n <ng-container *ngIf=\"item.facetValue\">\r\n <vdr-facet-value-chip\r\n [facetValue]=\"item.facetValue\"\r\n [removable]=\"true\"\r\n (remove)=\"clear(item)\"\r\n ></vdr-facet-value-chip>\r\n </ng-container>\r\n <ng-container *ngIf=\"!item.facetValue\">\r\n <vdr-chip [icon]=\"'times'\" (iconClick)=\"clear(item)\">\"{{ item.label }}\"</vdr-chip>\r\n </ng-container>\r\n </ng-template>\r\n <ng-template ng-option-tmp let-item=\"item\" let-index=\"index\" let-search=\"searchTerm\">\r\n <ng-container *ngIf=\"item.facetValue\">\r\n <vdr-facet-value-chip [facetValue]=\"item.facetValue\" [removable]=\"false\"></vdr-facet-value-chip>\r\n </ng-container>\r\n </ng-template>\r\n</ng-select>\r\n",
3355
- changeDetection: ChangeDetectionStrategy.OnPush,
3356
- providers: [{ provide: SELECTION_MODEL_FACTORY, useValue: ɵ0 }],
3357
- styles: [":host{margin-top:6px;display:block;width:100%}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-value{background:none;margin:0}:host ::ng-deep .ng-dropdown-panel-items div.ng-option:last-child{display:none}:host ::ng-deep .ng-dropdown-panel .ng-dropdown-header{border:none;padding:0}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container{padding:0}:host ::ng-deep .ng-select.ng-select-multiple .ng-select-container .ng-value-container .ng-placeholder{padding-left:8px}ng-select{width:100%;min-width:300px;margin-right:12px}.search-header{padding:8px 10px;border-bottom:1px solid var(--color-component-border-100);cursor:pointer}.search-header.selected,.search-header:hover{background-color:var(--color-component-bg-200)}\n"]
3358
- },] }
3359
- ];
3360
- ProductSearchInputComponent.propDecorators = {
3361
- facetValueResults: [{ type: Input }],
3362
- searchTermChange: [{ type: Output }],
3363
- facetValueChange: [{ type: Output }],
3364
- selectComponent: [{ type: ViewChild, args: ['selectComponent', { static: true },] }]
3365
- };
3366
-
3367
3392
  class UpdateProductOptionDialogComponent {
3368
3393
  constructor() {
3369
3394
  this.updateVariantName = true;
@@ -3601,7 +3626,7 @@ ProductVariantsListComponent.decorators = [
3601
3626
  selector: 'vdr-product-variants-list',
3602
3627
  template: "<div class=\"variants-list\">\r\n <div\r\n class=\"variant-container card\"\r\n *ngFor=\"\r\n let variant of variants | paginate: paginationConfig || { itemsPerPage: 10, currentPage: 1 };\r\n trackBy: trackById;\r\n let i = index\r\n \"\r\n [class.disabled]=\"!formGroupMap.get(variant.id)?.get('enabled')?.value\"\r\n >\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <div class=\"card-block header-row\">\r\n <div class=\"details\">\r\n <vdr-title-input class=\"sku\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"sku\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n <vdr-title-input class=\"name\" [readonly]=\"!(updatePermission | hasPermission)\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [placeholder]=\"'common.name' | translate\"\r\n />\r\n </clr-input-container>\r\n </vdr-title-input>\r\n </div>\r\n <div class=\"right-controls\">\r\n <clr-toggle-wrapper *vdrIfPermissions=\"updatePermission\">\r\n <input type=\"checkbox\" clrToggle name=\"enabled\" formControlName=\"enabled\" />\r\n <label>{{ 'common.enabled' | translate }}</label>\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"variant-body\">\r\n <div class=\"assets\">\r\n <vdr-assets\r\n [compact]=\"true\"\r\n [assets]=\"pendingAssetChanges[variant.id]?.assets || variant.assets\"\r\n [featuredAsset]=\"\r\n pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset\r\n \"\r\n [updatePermissions]=\"updatePermission\"\r\n (change)=\"onAssetChange(variant.id, $event)\"\r\n ></vdr-assets>\r\n </div>\r\n <div class=\"variant-form-inputs\">\r\n <div class=\"standard-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <div class=\"tax-category\">\r\n <clr-select-container\r\n *vdrIfPermissions=\"updatePermission; else taxCategoryLabel\"\r\n >\r\n <label>{{ 'catalog.tax-category' | translate }}</label>\r\n <select clrSelect name=\"options\" formControlName=\"taxCategoryId\">\r\n <option\r\n *ngFor=\"let taxCategory of taxCategories\"\r\n [value]=\"taxCategory.id\"\r\n >\r\n {{ taxCategory.name }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <ng-template #taxCategoryLabel>\r\n <label class=\"clr-control-label\">{{\r\n 'catalog.tax-category' | translate\r\n }}</label>\r\n <div class=\"tax-category-label\">\r\n {{ getTaxCategoryName(formGroup) }}\r\n </div>\r\n </ng-template>\r\n </div>\r\n <div class=\"price\">\r\n <clr-input-container>\r\n <label>{{ 'catalog.price' | translate }}</label>\r\n <vdr-currency-input\r\n *ngIf=\"!channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"price\"\r\n ></vdr-currency-input>\r\n <vdr-currency-input\r\n *ngIf=\"channelPriceIncludesTax\"\r\n clrInput\r\n [currencyCode]=\"variant.currencyCode\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"priceWithTax\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </div>\r\n <vdr-variant-price-detail\r\n [price]=\"formGroup.get('price')!.value\"\r\n [currencyCode]=\"variant.currencyCode\"\r\n [priceIncludesTax]=\"channelPriceIncludesTax\"\r\n [taxCategoryId]=\"formGroup.get('taxCategoryId')!.value\"\r\n ></vdr-variant-price-detail>\r\n </div>\r\n <div class=\"variant-form-input-row\">\r\n <clr-select-container *vdrIfPermissions=\"updatePermission\">\r\n <label\r\n >{{ 'catalog.track-inventory' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.track-inventory-tooltip' | translate\"\r\n ></vdr-help-tooltip>\r\n </label>\r\n <select clrSelect name=\"options\" formControlName=\"trackInventory\">\r\n <option [value]=\"GlobalFlag.TRUE\">\r\n {{ 'catalog.track-inventory-true' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.FALSE\">\r\n {{ 'catalog.track-inventory-false' | translate }}\r\n </option>\r\n <option [value]=\"GlobalFlag.INHERIT\">\r\n {{ 'catalog.track-inventory-inherit' | translate }}\r\n </option>\r\n </select>\r\n </clr-select-container>\r\n <clr-input-container>\r\n <label\r\n >{{ 'catalog.stock-on-hand' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-on-hand-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <input\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n clrInput\r\n type=\"number\"\r\n [min]=\"getStockOnHandMinValue(formGroup)\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"inventoryIsNotTracked(formGroup)\"\r\n />\r\n </clr-input-container>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-allocated' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-allocated-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ variant.stockAllocated }}\r\n </div>\r\n </div>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-saleable' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-saleable-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ getSaleableStockLevel(variant) }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"variant-form-input-row\">\r\n <div\r\n class=\"out-of-stock-threshold-wrapper\"\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n >\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.out-of-stock-threshold' | translate\r\n }}<vdr-help-tooltip\r\n [content]=\"'catalog.out-of-stock-threshold-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"flex\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [formControl]=\"formGroup.get('outOfStockThreshold')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"\r\n formGroup.get('useGlobalOutOfStockThreshold')?.value !==\r\n false || inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n </clr-input-container>\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"useGlobalOutOfStockThreshold\"\r\n formControlName=\"useGlobalOutOfStockThreshold\"\r\n [vdrDisabled]=\"\r\n !(updatePermission | hasPermission) ||\r\n inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n <label\r\n >{{ 'catalog.use-global-value' | translate }} ({{\r\n globalOutOfStockThreshold\r\n }})</label\r\n >\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"custom-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductVariant\"\r\n [customFields]=\"customFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"formGroup.get('customFields')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"options-facets\">\r\n <vdr-entity-info [entity]=\"variant\"></vdr-entity-info>\r\n <div *ngIf=\"variant.options.length\">\r\n <div class=\"options\">\r\n <vdr-chip\r\n *ngFor=\"let option of variant.options | sort: 'groupId'\"\r\n [colorFrom]=\"optionGroupName(option.groupId)\"\r\n [invert]=\"true\"\r\n (iconClick)=\"editOption(option)\"\r\n [icon]=\"(updatePermission | hasPermission) && 'pencil'\"\r\n >\r\n <span class=\"option-group-name\">{{ optionGroupName(option.groupId) }}</span>\r\n {{ optionName(option) }}\r\n </vdr-chip>\r\n <a [routerLink]=\"['./', 'options']\" class=\"btn btn-link btn-sm\"\r\n >{{ 'catalog.edit-options' | translate }}...</a\r\n >\r\n </div>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of existingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of pendingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-sm btn-secondary\"\r\n (click)=\"selectFacetValueClick.emit([variant.id])\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-container *vdrIfMultichannel>\r\n <div class=\"card-block\" *vdrIfDefaultChannelActive>\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of variant.channels\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n [title]=\"'catalog.remove-from-channel' | translate\"\r\n (iconClick)=\"\r\n removeFromChannel.emit({ channelId: channel.id, variant: variant })\r\n \"\r\n >\r\n <vdr-channel-badge [channelCode]=\"channel.code\"></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel.emit(variant)\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n</div>\r\n",
3603
3628
  changeDetection: ChangeDetectionStrategy.OnPush,
3604
- styles: [".with-selected{display:flex;min-height:52px;align-items:center;border:1px solid var(--color-component-border-100);border-radius:3px;padding:6px 18px}.with-selected vdr-select-toggle{margin-right:12px}.with-selected>label{margin-right:12px}.variant-container{transition:background-color .2s;min-height:330px}.variant-container.disabled{background-color:var(--color-component-bg-200)}.variant-container .header-row{display:flex;align-items:center;flex-wrap:wrap}.variant-container .variant-body{display:flex;flex-direction:column}@media screen and (min-width: 768px){.variant-container .variant-body{flex-direction:row}}.variant-container .details{display:flex;flex-direction:column;flex:1;margin-right:12px}@media screen and (min-width: 768px){.variant-container .details{flex-direction:row;height:36px}}.variant-container .details .name{flex:1}.variant-container .details .name ::ng-deep .clr-control-container{width:100%}.variant-container .details .name ::ng-deep .clr-control-container input.clr-input{min-width:100%}.variant-container .details .sku{width:160px;margin-right:20px;flex:0}.variant-container .details ::ng-deep .name input{min-width:300px}.variant-container .right-controls{display:flex}.variant-container .tax-category-label{margin-top:3px}.variant-container .variant-form-inputs{flex:1;display:flex;flex-direction:column}@media screen and (min-width: 768px){.variant-container .variant-form-inputs{flex-direction:row}}.variant-container .variant-form-input-row{display:flex;flex-wrap:wrap}@media screen and (min-width: 768px){.variant-container .variant-form-input-row{margin:0 6px 8px 24px}}.variant-container .variant-form-input-row>*{margin-right:24px;margin-bottom:24px}.variant-container .track-inventory-toggle{margin-top:22px}.variant-container .clr-form-control{margin-top:0}.variant-container .facets{display:flex;flex-wrap:wrap;align-items:center}.variant-container .pricing{display:flex}.variant-container .pricing>div{margin-right:12px}.variant-container .option-group-name{color:var(--color-text-200);text-transform:uppercase;font-size:10px;margin-right:3px;height:11px}.variant-container .options-facets{display:flex;color:var(--color-grey-400)}.variant-container ::ng-deep .clr-control-container{width:100%}.channel-assignment{justify-content:flex-end}.channel-assignment .btn{margin:6px 12px 6px 0}.out-of-stock-threshold-wrapper{display:flex;flex-direction:column}.out-of-stock-threshold-wrapper clr-toggle-wrapper{margin-left:24px}.inventory-untracked{opacity:.5}\n"]
3629
+ styles: [".with-selected{display:flex;min-height:52px;align-items:center;border:1px solid var(--color-component-border-100);border-radius:3px;padding:6px 18px}.with-selected vdr-select-toggle{margin-right:12px}.with-selected>label{margin-right:12px}.variant-container{transition:background-color .2s;min-height:330px}.variant-container.disabled{background-color:var(--color-component-bg-200)}.variant-container .header-row{display:flex;align-items:center;flex-wrap:wrap}.variant-container .variant-body{display:flex;flex-direction:column}@media screen and (min-width: 768px){.variant-container .variant-body{flex-direction:row}}.variant-container .details{display:flex;flex-direction:column;flex:1;margin-right:12px}@media screen and (min-width: 768px){.variant-container .details{flex-direction:row;height:36px}}.variant-container .details .name{flex:1}.variant-container .details .name ::ng-deep .clr-control-container{width:100%}.variant-container .details .name ::ng-deep .clr-control-container input.clr-input{min-width:100%}.variant-container .details .sku{width:160px;margin-right:20px;flex:0}.variant-container .details ::ng-deep .name input{min-width:300px}.variant-container .right-controls{display:flex}.variant-container .tax-category-label{margin-top:3px}.variant-container .variant-form-inputs{flex:1;display:flex;flex-direction:column}@media screen and (min-width: 768px){.variant-container .variant-form-inputs{flex-direction:row}}.variant-container .variant-form-input-row{display:flex;flex-wrap:wrap}@media screen and (min-width: 768px){.variant-container .variant-form-input-row{margin:0 6px 8px 24px}}.variant-container .variant-form-input-row>*{margin-right:24px;margin-bottom:24px}.variant-container .track-inventory-toggle{margin-top:22px}.variant-container .clr-form-control{margin-top:0}.variant-container .facets{display:flex;flex-wrap:wrap;align-items:center}.variant-container .pricing{display:flex}.variant-container .pricing>div{margin-right:12px}.variant-container .option-group-name{color:var(--color-text-200);text-transform:uppercase;font-size:10px;margin-right:3px;height:11px}.variant-container .options-facets{display:flex;color:var(--color-grey-400)}.variant-container ::ng-deep .clr-control-container{width:100%}.channel-assignment{justify-content:flex-end;flex-wrap:wrap;max-height:110px;overflow-y:auto}.channel-assignment .btn{margin:6px 12px 6px 0}.out-of-stock-threshold-wrapper{display:flex;flex-direction:column}.out-of-stock-threshold-wrapper clr-toggle-wrapper{margin-left:24px}.inventory-untracked{opacity:.5}\n"]
3605
3630
  },] }
3606
3631
  ];
3607
3632
  ProductVariantsListComponent.ctorParameters = () => [
@@ -3765,7 +3790,6 @@ const CATALOG_COMPONENTS = [
3765
3790
  CollectionTreeNodeComponent,
3766
3791
  CollectionContentsComponent,
3767
3792
  ProductVariantsTableComponent,
3768
- ProductSearchInputComponent,
3769
3793
  OptionValueInputComponent,
3770
3794
  UpdateProductOptionDialogComponent,
3771
3795
  ProductVariantsEditorComponent,
@@ -3790,5 +3814,5 @@ CatalogModule.decorators = [
3790
3814
  * Generated bundle index. Do not edit.
3791
3815
  */
3792
3816
 
3793
- export { ApplyFacetDialogComponent, AssetDetailComponent, AssetListComponent, AssetResolver, AssetsComponent, AssignProductsToChannelDialogComponent, CatalogModule, CollectionContentsComponent, CollectionDetailComponent, CollectionListComponent, CollectionResolver, CollectionTreeComponent, CollectionTreeNodeComponent, ConfirmVariantDeletionDialogComponent, FacetDetailComponent, FacetListComponent, FacetResolver, GenerateProductVariantsComponent, GeneratedVariant, OPTION_VALUE_INPUT_VALUE_ACCESSOR, OptionValueInputComponent, ProductDetailComponent, ProductDetailService, ProductListComponent, ProductOptionsEditorComponent, ProductResolver, ProductSearchInputComponent, ProductVariantsEditorComponent, ProductVariantsListComponent, ProductVariantsResolver, ProductVariantsTableComponent, UpdateProductOptionDialogComponent, VariantPriceDetailComponent, arrayToTree, assetBreadcrumb, catalogRoutes, collectionBreadcrumb, facetBreadcrumb, productBreadcrumb, productOptionsEditorBreadcrumb, productVariantEditorBreadcrumb, replaceLast, ɵ1, ɵ2, ɵ3, ɵ4, ɵ5, ɵ6, ɵ7, ɵ8, ɵ9 };
3817
+ export { ApplyFacetDialogComponent, AssetDetailComponent, AssetListComponent, AssetResolver, AssetsComponent, AssignProductsToChannelDialogComponent, CatalogModule, CollectionContentsComponent, CollectionDetailComponent, CollectionListComponent, CollectionResolver, CollectionTreeComponent, CollectionTreeNodeComponent, ConfirmVariantDeletionDialogComponent, FacetDetailComponent, FacetListComponent, FacetResolver, GenerateProductVariantsComponent, GeneratedVariant, OPTION_VALUE_INPUT_VALUE_ACCESSOR, OptionValueInputComponent, ProductDetailComponent, ProductDetailService, ProductListComponent, ProductOptionsEditorComponent, ProductResolver, ProductVariantsEditorComponent, ProductVariantsListComponent, ProductVariantsResolver, ProductVariantsTableComponent, UpdateProductOptionDialogComponent, VariantPriceDetailComponent, arrayToTree, assetBreadcrumb, catalogRoutes, collectionBreadcrumb, facetBreadcrumb, productBreadcrumb, productOptionsEditorBreadcrumb, productVariantEditorBreadcrumb, replaceLast, ɵ0, ɵ1, ɵ2, ɵ3, ɵ4, ɵ5, ɵ6, ɵ7, ɵ8, ɵ9 };
3794
3818
  //# sourceMappingURL=vendure-admin-ui-catalog.js.map