@vendure/admin-ui-plugin 2.0.0-next.2 → 2.0.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/admin-ui/165.6aeb6ecf722558ee.js.map +1 -1
- package/lib/admin-ui/239.e2e63f2ccd517604.js +2 -0
- package/lib/admin-ui/239.e2e63f2ccd517604.js.map +1 -0
- package/lib/admin-ui/26.5cc3bfffe8943e16.js +2 -0
- package/lib/admin-ui/26.5cc3bfffe8943e16.js.map +1 -0
- package/lib/admin-ui/316.265d65a6a9d1b4c0.js +2 -0
- package/lib/admin-ui/{316.07f9c805e4c95dc8.js.map → 316.265d65a6a9d1b4c0.js.map} +1 -1
- package/lib/admin-ui/356.975f7f2d201afda5.js +2 -0
- package/lib/admin-ui/356.975f7f2d201afda5.js.map +1 -0
- package/lib/admin-ui/3rdpartylicenses.txt +23 -0
- package/lib/admin-ui/407.a3fde1da25c0935c.js +12 -0
- package/lib/admin-ui/407.a3fde1da25c0935c.js.map +1 -0
- package/lib/admin-ui/451.a7fd4069c4f4c687.js +65 -0
- package/lib/admin-ui/451.a7fd4069c4f4c687.js.map +1 -0
- package/lib/admin-ui/600.17470a2c90aa79d8.js +2 -0
- package/lib/admin-ui/600.17470a2c90aa79d8.js.map +1 -0
- package/lib/admin-ui/625.3c0c5821b952b58e.js +2 -0
- package/lib/admin-ui/{625.adebc6a7222bde82.js.map → 625.3c0c5821b952b58e.js.map} +1 -1
- package/lib/admin-ui/i18n-messages/cs.json +50 -3
- package/lib/admin-ui/i18n-messages/de.json +53 -3
- package/lib/admin-ui/i18n-messages/en.json +55 -8
- package/lib/admin-ui/i18n-messages/es.json +50 -3
- package/lib/admin-ui/i18n-messages/fr.json +50 -3
- package/lib/admin-ui/i18n-messages/it.json +50 -3
- package/lib/admin-ui/i18n-messages/pl.json +50 -3
- package/lib/admin-ui/i18n-messages/pt_BR.json +50 -3
- package/lib/admin-ui/i18n-messages/pt_PT.json +50 -3
- package/lib/admin-ui/i18n-messages/ru.json +50 -3
- package/lib/admin-ui/i18n-messages/uk.json +50 -3
- package/lib/admin-ui/i18n-messages/zh_Hans.json +50 -3
- package/lib/admin-ui/i18n-messages/zh_Hant.json +50 -3
- package/lib/admin-ui/index.html +2 -2
- package/lib/admin-ui/main.65109179713dd228.js +2944 -0
- package/lib/admin-ui/main.65109179713dd228.js.map +1 -0
- package/lib/admin-ui/runtime.28bd5da02a9b1f7b.js +2 -0
- package/lib/admin-ui/{runtime.1dd1cbaf09547dd2.js.map → runtime.28bd5da02a9b1f7b.js.map} +1 -1
- package/lib/admin-ui/styles/_variables.scss +4 -0
- package/lib/admin-ui/styles/global/_forms.scss +8 -7
- package/lib/admin-ui/styles/global/_overrides.scss +11 -1
- package/lib/admin-ui/styles/global/_sass-overrides.scss +3 -0
- package/lib/admin-ui/styles/global/_utilities.scss +14 -0
- package/lib/admin-ui/styles/styles.scss +1 -0
- package/lib/admin-ui/styles/theme/default.scss +13 -1
- package/lib/admin-ui/styles/ui-extension-theme.scss +1 -0
- package/lib/admin-ui/{styles.fb1aaa9a9baed129.css → styles.88d3f0120bfc894a.css} +2 -2
- package/lib/admin-ui/styles.88d3f0120bfc894a.css.map +1 -0
- package/package.json +4 -4
- package/lib/admin-ui/239.a68e402e10b798f1.js +0 -2
- package/lib/admin-ui/239.a68e402e10b798f1.js.map +0 -1
- package/lib/admin-ui/26.477d6446134d960e.js +0 -2
- package/lib/admin-ui/26.477d6446134d960e.js.map +0 -1
- package/lib/admin-ui/316.07f9c805e4c95dc8.js +0 -2
- package/lib/admin-ui/349.abe4847f7fe9b3da.js +0 -2
- package/lib/admin-ui/349.abe4847f7fe9b3da.js.map +0 -1
- package/lib/admin-ui/356.3a6951fe80b5a001.js +0 -2
- package/lib/admin-ui/356.3a6951fe80b5a001.js.map +0 -1
- package/lib/admin-ui/600.8f0165a8d1255cd0.js +0 -2
- package/lib/admin-ui/600.8f0165a8d1255cd0.js.map +0 -1
- package/lib/admin-ui/625.adebc6a7222bde82.js +0 -2
- package/lib/admin-ui/849.cc032ddf77c67cc3.js +0 -2
- package/lib/admin-ui/849.cc032ddf77c67cc3.js.map +0 -1
- package/lib/admin-ui/main.0b0d9a8ae6759254.js +0 -2740
- package/lib/admin-ui/main.0b0d9a8ae6759254.js.map +0 -1
- package/lib/admin-ui/runtime.1dd1cbaf09547dd2.js +0 -2
- package/lib/admin-ui/styles.fb1aaa9a9baed129.css.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["t","save","s","constructor","n","e","o","a","r","c","super","this","l","customFields","getCustomFieldConfig","ngOnInit","detailForm","name","tags","formBuilder","group","reduce","Object","init","ngOnDestroy","destroy","onAssetChange","get","setValue","markAsDirty","dataService","product","updateAsset","id","value","subscribe","notificationService","success","entity","error","setFormValues","length","setCustomFieldFormValues","X","selectors","B","setQueryFn","getAssetList","assets","d","h","searchTerm$","_","p","filterByTags$","map","f","options","skip","take","filter","contains","sort","createdAt","tagsOperator","paginationConfig$","itemsPerPage$","currentPage$","totalItems$","pipe","C","itemsPerPage","currentPage","totalItems","destroy$","refresh","allTags$","getTagList","mapStream","items","filesSelected","uploading","createAssets","Je","__typename","message","count","deleteAssets","showModalAndDelete","result","modalService","dialog","title","m","translationVars","body","buttons","type","label","returnValue","y","U","et","selectAssets","oxw","dropListDropped","previewAsset","setAsFeatured","removeAsset","assetsSetter","slice","fromComponent","size","Nt","concat","featuredAsset","emitChangeEvent","changeDetector","markForCheck","isFeatured","closable","locals","asset","change","emit","previousContainer","data","container","$","Qt","contentsCurrentPage$","route","paramMap","contentsItemsPerPage$","Mt","filterTermControl","valueChanges","tt","setContentsPageNumber","collectionIdChange$","refresh$","collection","getCollectionContents","mapSingle","M","contents$","productVariants","contentsTotalItems$","ngOnChanges","next","collectionId","currentValue","complete","setParam","setContentsItemsPerPage","router","navigate","snapshot","params","relativeTo","queryParamsHandling","z","create","removeFilter","addFilter","updateSlug","slug","description","visible","inheritFilters","filters","array","getCollectionFilters","single$","allFilters","collectionFilters","getFilterDefinition","find","code","assetsChanged","values","assetChanges","entity$","languageCode$","w","pristine","findIndex","args","push","control","removeAt","splice","dirty","O","getUpdatedCollection","parentId","createCollection","markAsPristine","updateCollection","contentsComponent","canDeactivate","patchValue","isPrivate","forEach","translatable","updatedFields","customFieldConfig","languageCode","defaultTranslation","assetIds","featuredAssetId","mapOperationsToInputs","arguments","ct","i","Map","set","children","Tn","hasOwnProperty","expanded","parent","rearrange$","_rearrange$","asObservable","delete$","_delete$","setCollectionTree","collectionTree","resetMoveList","allMoveListItems","getMoveListItems","calculateAllMoveListItems","ancestorIdPath","has","onDrop","item","Error","index","currentIndex","onMove","onDelete","path","join","Set","Q","factory","move","moveUp","moveDown","delete","depth","parentName","client","userStatus","permissions","kt","hasUpdatePermission$","includes","hasDeletePermission$","expandAll","previousValue","trackByFn","moveListItems","collectionTreeService","drop","previousIndex","Y","pipes","collections","le","rearrange","deleteCollection","lt","closeContents","queryResult","getCollections","refetchOnChannelChange","items$","activeCollectionId$","activeCollectionTitle$","availableLanguages$","serverConfigService","getAvailableLanguages","contentLanguage$","uiState","contentLanguage","Dt","q","completed$","onRearrange","moveCollection","contents","setLanguage","setContentLanguage","ref","refetch","dt","updateValueCode","deleteFacetValue","addFacetValue","updateCode","customValueFields","facet","customValueFieldIsSet","getValuesFormArray","addControl","insert","getUpdatedFacet","createFacet","getAllFacets","updateFacet","getCreatedFacetValues","createFacetValues","getFacet","getUpdatedFacetValues","updateFacetValues","D","deleteFacetValues","x","b","at","T","I","N","It","Ht","controls","translations","facetId","toString","k","pt","toggleDisplayLimit","deleteFacet","getFacets","facets","po","de","displayLimit","initialLimit","ut","cancel","selectValues","ngAfterViewInit","setTimeout","selector","focus","resolveWith","selectedValues","mt","assign","isProductVariantMode","productVariantIds","activeChannelId","settings","getChannels","channels","currentChannel","availableChannels","selectedChannelIdControl","selectChannel","variantsPreview$","Vo","getTopVariants","priceFactorControl","price","pricePreview","selectedChannel","assignVariantsToChannel","channelId","priceFactor","channel","assignProductsToChannel","productIds","getProduct","variantList","toPromise","K","lastIndexOf","substr","replace","getTaxCategories","taxCategories","createProductWithVariants","createProduct","groups","createProductOptionGroups","P","addOptionGroupToProduct","productId","optionGroupId","optionGroups","variants","optionValues","optionIds","createProductVariants","createProductOptionGroup","sku","stockOnHand","stock","updateProduct","autoUpdate","productInput","variantsInput","getProductVariants","Bt","Me","ie","St","ne","updateProductVariants","updateProductOption","deleteProductVariant","Bo","zo","G","removeOption","Ce","provide","useExisting","E","multi","registerOnChange","onChangeFn","registerOnTouched","onTouchFn","setDisabledState","disabled","writeValue","textArea","nativeElement","locked","handleKey","key","addOptionValue","preventDefault","lastSelected","removeLastOption","input","handleBlur","isFocussed","parseInputIntoOptions","split","trim","decls","handleEnter","generateVariants","onFormChange","oe","getActiveChannel","currencyCode","activeChannel","addOption","variantFormValues","enabled","copyFromDefault","stopPropagation","variantsChange","_t","subscription","formArray","buildFormGroupMap","unsubscribe","getFeaturedAsset","pendingAssetChanges","optionGroupName","formGroupMap","clear","gt","update","productOption","activeLanguage","customFieldsForm","updateVariantName","codeInputTouched","ht","getTaxRatesSimple","taxRates","taxRate$","taxCategoryIdChange$","defaultTaxZone","zone","category","grossPrice$","priceChange$","Math","round","taxCategoryId","ft","editOption","removeFacetValue","selectFacetValueClick","removeFromChannel","assignToChannel","getGlobalSettings","globalSettings","globalTrackInventory","trackInventory","globalOutOfStockThreshold","outOfStockThreshold","add","facetValues","isDefaultChannel","pe","trackById","inventoryIsNotTracked","getTaxCategoryName","getSaleableStockLevel","useGlobalOutOfStockThreshold","stockAllocated","areAllSelected","selectedVariantIds","assetChange","variantId","toggleSelectAll","selectionChange","toggleSelectVariant","indexOf","optionName","pendingFacetValues","getFacetValueIds","existingFacetValues","facetValueIds","isVariantSelected","customOptionFields","vt","removeProductFacetValue","selectProductFacetValue","setItemsPerPage","setPage","assignVariantToChannel","removeVariantFromChannel","variantAssetChange","selectVariantFacetValue","filterInput","navigateToTab","customVariantFields","customOptionGroupFields","autoUpdateVariantNames","product$","Ut","Fo","me","Oo","filterOperator","bufferSize","refCount","variants$","ue","productVariantMap","taxCategories$","productDetailService","activeTab$","buildVariantFormArray","facets$","getProductFormGroup","facetValues$","productChannels$","channelPriceIncludesTax$","pricesIncludeTax","location","replaceState","createUrlTree","tab","currentChannelIds","removeProductsFromChannel","variant","removeVariantsFromChannel","variantAssetsChanged","keys","variantAssetChanges","displayFacetValueModal","_e","variantFacetValueChanges","variantsToCreateAreValid","createVariantsConfig","every","getUpdatedProduct","console","getUpdatedProductVariants","updateSlugAfterSave","priceWithTax","taxCategory","emitEvent","Ct","selectTag","isFacetValueItem","toLowerCase","facetValue","toLocaleLowerCase","setSearchTerm","selectComponent","select","selectedItems","unselect","setFacetValues","onSelectChange","Array","isArray","lastTerm","searchTermChange","lastFacetValueIds","facetValueChange","addTagFn","isSearchHeaderSelected","itemsList","markedIndex","xt","qt","useValue","runPendingSearchIndexUpdates","deleteProduct","queryParamMap","searchTerm","productSearchInput","selectedFacetValueIds$","getAll","searchProducts","search","term","facetValueOperator","groupByProduct","result$","getPendingSearchIndexUpdates","pendingSearchIndexUpdates","setQueryParam","page","setFacetValueIds","fvids","rebuildSearchIndex","reindex","info","jobQueueService","addJob","state","Intl","NumberFormat","format","duration","indexedItemCount","time","bt","optionGroupCustomFields","optionCustomFields","optionGroups$","getOptionGroups","getOptions","invalid","getUpdatedOptionGroup","updateProductOptionGroup","getUpdatedOption","updatedAt","setControl","Zt","confirm","onFormChanged","deleteVariant","Tt","initOptionsAndVariants","formValueChanged","getVariantsToAdd","generatedVariants","existing","getVariantName","isNew","getVariantPrototype","Te","productVariantId","isDefault","optionsAreEqual","optionsAreSubset","ja","reFetchProduct","checkUniqueSkus","confirmDeletionOfObsoleteVariants","addOptionGroupsToProduct","addNewOptionsToGroups","fetchOptionGroups","createNewProductVariants","deleteObsoleteVariants","getObsoleteVariants","hasOnlyDefaultVariant","productOptionGroupId","addOptionToGroup","getProductOptionGroup","productOptionGroup","getProductVariantsOptions","toOptionString","At","fileSize","mimeType","width","height","source","preview","focalPoint","getAsset","Pt","getCollection","yt","Ft","Ot","W","Ae","component","breadcrumb","resolve","Pe","ye","Fe","Oe","Ie","Le","breadcrumbKey","getName","link","wt","Z"],"sources":["./src/lib/catalog/src/components/asset-detail/asset-detail.component.html","./src/lib/catalog/src/components/asset-detail/asset-detail.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.html","./src/lib/catalog/src/components/assets/assets.component.html","./src/lib/catalog/src/components/assets/assets.component.ts","./src/lib/catalog/src/components/collection-contents/collection-contents.component.html","./src/lib/catalog/src/components/collection-contents/collection-contents.component.ts","./src/lib/catalog/src/components/collection-detail/collection-detail.component.html","./src/lib/catalog/src/components/collection-detail/collection-detail.component.ts","./src/lib/catalog/src/components/collection-tree/array-to-tree.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.service.ts","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree.component.ts","./src/lib/catalog/src/components/collection-list/collection-list.component.html","./src/lib/catalog/src/components/collection-list/collection-list.component.ts","./src/lib/catalog/src/components/facet-detail/facet-detail.component.html","./src/lib/catalog/src/components/facet-detail/facet-detail.component.ts","./src/lib/catalog/src/components/facet-list/facet-list.component.html","./src/lib/catalog/src/components/facet-list/facet-list.component.ts","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.html","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.ts","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.ts","./src/lib/catalog/src/providers/product-detail/replace-last.ts","./src/lib/catalog/src/providers/product-detail/product-detail.service.ts","./node_modules/@angular-devkit/build-angular/src/babel/webpack-loader.js","./src/lib/catalog/src/components/option-value-input/option-value-input.component.html","./src/lib/catalog/src/components/option-value-input/option-value-input.component.ts","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.html","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.html","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.ts","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.html","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.ts","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.html","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.ts","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.html","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.ts","./src/lib/catalog/src/components/product-detail/product-detail.component.html","./src/lib/catalog/src/components/product-detail/product-detail.component.ts","./src/lib/catalog/src/components/product-search-input/product-search-input.component.html","./src/lib/catalog/src/components/product-search-input/product-search-input.component.ts","./src/lib/catalog/src/components/product-list/product-list.component.html","./src/lib/catalog/src/components/product-list/product-list.component.ts","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.html","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.ts","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.html","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.ts","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.html","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts","./src/lib/catalog/src/providers/routing/asset-resolver.ts","./src/lib/catalog/src/providers/routing/collection-resolver.ts","./src/lib/catalog/src/providers/routing/facet-resolver.ts","./src/lib/catalog/src/providers/routing/product-resolver.ts","./src/lib/catalog/src/providers/routing/product-variants-resolver.ts","./src/lib/catalog/src/catalog.routes.ts","./src/lib/catalog/src/catalog.module.ts"],"sourcesContent":["<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-detail\"></vdr-action-bar-items>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateAsset']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<vdr-asset-preview\r\n [asset]=\"entity$ | async\"\r\n [editable]=\"true\"\r\n [customFields]=\"customFields\"\r\n [customFieldsForm]=\"detailForm.get('customFields')\"\r\n (assetChange)=\"onAssetChange($event)\"\r\n></vdr-asset-preview>\r\n","import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormBuilder, FormControl, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n CustomFieldConfig,\r\n DataService,\r\n GetAssetQuery,\r\n LanguageCode,\r\n NotificationService,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-asset-detail',\r\n templateUrl: './asset-detail.component.html',\r\n styleUrls: ['./asset-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetAssetQuery['asset']>>\r\n implements OnInit, OnDestroy\r\n{\r\n detailForm = new FormGroup({});\r\n customFields: CustomFieldConfig[];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Asset');\r\n }\r\n\r\n ngOnInit() {\r\n this.detailForm = new FormGroup({\r\n name: new FormControl(''),\r\n tags: new FormControl([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n onAssetChange(event: { id: string; name: string; tags: string[] }) {\r\n this.detailForm.get('name')?.setValue(event.name);\r\n this.detailForm.get('tags')?.setValue(event.tags);\r\n this.detailForm.markAsDirty();\r\n }\r\n\r\n save() {\r\n this.dataService.product\r\n .updateAsset({\r\n id: this.id,\r\n name: this.detailForm.value.name,\r\n tags: this.detailForm.value.tags,\r\n customFields: this.detailForm.value.customFields,\r\n })\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Asset' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Asset',\r\n });\r\n },\r\n );\r\n }\r\n\r\n protected setFormValues(entity: NonNullable<GetAssetQuery['asset']>, languageCode: LanguageCode): void {\r\n this.detailForm.get('name')?.setValue(entity.name);\r\n this.detailForm.get('tags')?.setValue(entity.tags);\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(this.customFields, this.detailForm.get(['customFields']), entity);\r\n }\r\n }\r\n}\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetAssetListQuery,\r\n GetAssetListQueryVariables,\r\n ItemOf,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SortOrder,\r\n TagFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { PaginationInstance } from 'ngx-pagination';\r\nimport { BehaviorSubject, combineLatest, EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, finalize, map, switchMap, takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-asset-list',\r\n templateUrl: './asset-list.component.html',\r\n styleUrls: ['./asset-list.component.scss'],\r\n})\r\nexport class AssetListComponent\r\n extends BaseListComponent<\r\n GetAssetListQuery,\r\n ItemOf<GetAssetListQuery, 'assets'>,\r\n GetAssetListQueryVariables\r\n >\r\n implements OnInit\r\n{\r\n searchTerm$ = new BehaviorSubject<string | undefined>(undefined);\r\n filterByTags$ = new BehaviorSubject<TagFragment[] | undefined>(undefined);\r\n uploading = false;\r\n allTags$: Observable<TagFragment[]>;\r\n paginationConfig$: Observable<PaginationInstance>;\r\n\r\n constructor(\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.product.getAssetList(...args),\r\n data => data.assets,\r\n (skip, take) => {\r\n const searchTerm = this.searchTerm$.value;\r\n const tags = this.filterByTags$.value?.map(t => t.value);\r\n return {\r\n options: {\r\n skip,\r\n take,\r\n ...(searchTerm\r\n ? {\r\n filter: {\r\n name: { contains: searchTerm },\r\n },\r\n }\r\n : {}),\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n tags,\r\n tagsOperator: LogicalOperator.AND,\r\n },\r\n };\r\n },\r\n { take: 25, skip: 0 },\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.paginationConfig$ = combineLatest(this.itemsPerPage$, this.currentPage$, this.totalItems$).pipe(\r\n map(([itemsPerPage, currentPage, totalItems]) => ({ itemsPerPage, currentPage, totalItems })),\r\n );\r\n this.searchTerm$.pipe(debounceTime(250), takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n\r\n this.filterByTags$.pipe(takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n this.allTags$ = this.dataService.product.getTagList().mapStream(data => data.tags.items);\r\n }\r\n\r\n filesSelected(files: File[]) {\r\n if (files.length) {\r\n this.uploading = true;\r\n this.dataService.product\r\n .createAssets(files)\r\n .pipe(finalize(() => (this.uploading = false)))\r\n .subscribe(({ createAssets }) => {\r\n let successCount = 0;\r\n for (const result of createAssets) {\r\n switch (result.__typename) {\r\n case 'Asset':\r\n successCount++;\r\n break;\r\n case 'MimeTypeError':\r\n this.notificationService.error(result.message);\r\n break;\r\n }\r\n }\r\n if (0 < successCount) {\r\n super.refresh();\r\n this.notificationService.success(_('asset.notify-create-assets-success'), {\r\n count: successCount,\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n deleteAssets(assets: Asset[]) {\r\n this.showModalAndDelete(assets.map(a => a.id))\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(\r\n assets.map(a => a.id),\r\n response.message || '',\r\n ).pipe(map(r => r.result === DeletionResult.DELETED));\r\n }\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Assets',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Assets',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(assetIds: string[], message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-assets'),\r\n translationVars: {\r\n count: assetIds.length,\r\n },\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.product.deleteAssets(assetIds, !!message) : EMPTY)),\r\n map(res => res.deleteAssets),\r\n );\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <vdr-asset-search-input\r\n class=\"pr4 mt1\"\r\n [tags]=\"allTags$ | async\"\r\n (searchTermChange)=\"searchTerm$.next($event)\"\r\n (tagsChange)=\"filterByTags$.next($event)\"\r\n ></vdr-asset-search-input>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-list\"></vdr-action-bar-items>\r\n <vdr-asset-file-input\r\n (selectFiles)=\"filesSelected($event)\"\r\n [uploading]=\"uploading\"\r\n dropZoneTarget=\".content-area\"\r\n ></vdr-asset-file-input>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-asset-gallery\r\n [assets]=\"(items$ | async)! | paginate: (paginationConfig$ | async) || {}\"\r\n [multiSelect]=\"true\"\r\n [canDelete]=\"['DeleteCatalog', 'DeleteAsset'] | hasPermission\"\r\n (deleteAssets)=\"deleteAssets($event)\"\r\n></vdr-asset-gallery>\r\n\r\n<div class=\"paging-controls\">\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 [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n ></vdr-pagination-controls>\r\n</div>\r\n","<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","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n HostBinding,\r\n Input,\r\n Output,\r\n} from '@angular/core';\r\nimport {\r\n Asset,\r\n AssetPickerDialogComponent,\r\n AssetPreviewDialogComponent,\r\n ModalService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport interface AssetChange {\r\n assets: Asset[];\r\n featuredAsset: Asset | undefined;\r\n}\r\n\r\n/**\r\n * A component which displays the Assets, and allows assets to be removed and\r\n * added, and for the featured asset to be set.\r\n *\r\n * Note: rather complex code for drag drop is due to a limitation of the default CDK implementation\r\n * which is addressed by a work-around from here: https://github.com/angular/components/issues/13372#issuecomment-483998378\r\n */\r\n@Component({\r\n selector: 'vdr-assets',\r\n templateUrl: './assets.component.html',\r\n styleUrls: ['./assets.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetsComponent {\r\n @Input('assets') set assetsSetter(val: Asset[]) {\r\n // create a new non-readonly array of assets\r\n this.assets = (val || []).slice();\r\n }\r\n\r\n @Input() featuredAsset: Asset | undefined;\r\n @HostBinding('class.compact')\r\n @Input()\r\n compact = false;\r\n @Output() change = new EventEmitter<AssetChange>();\r\n\r\n public assets: Asset[] = [];\r\n\r\n @Input()\r\n updatePermissions: string | string[] | Permission | Permission[];\r\n\r\n constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}\r\n\r\n selectAssets() {\r\n this.modalService\r\n .fromComponent(AssetPickerDialogComponent, {\r\n size: 'xl',\r\n })\r\n .subscribe(result => {\r\n if (result && result.length) {\r\n this.assets = unique(this.assets.concat(result), 'id');\r\n if (!this.featuredAsset) {\r\n this.featuredAsset = result[0];\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n setAsFeatured(asset: Asset) {\r\n this.featuredAsset = asset;\r\n this.emitChangeEvent(this.assets, asset);\r\n }\r\n\r\n isFeatured(asset: Asset): boolean {\r\n return !!this.featuredAsset && this.featuredAsset.id === asset.id;\r\n }\r\n\r\n previewAsset(asset: Asset) {\r\n this.modalService\r\n .fromComponent(AssetPreviewDialogComponent, {\r\n size: 'xl',\r\n closable: true,\r\n locals: { asset },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeAsset(asset: Asset) {\r\n this.assets = this.assets.filter(a => a.id !== asset.id);\r\n if (this.featuredAsset && this.featuredAsset.id === asset.id) {\r\n this.featuredAsset = this.assets.length > 0 ? this.assets[0] : undefined;\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n\r\n private emitChangeEvent(assets: Asset[], featuredAsset: Asset | undefined) {\r\n this.change.emit({\r\n assets,\r\n featuredAsset,\r\n });\r\n }\r\n\r\n dropListDropped(event: CdkDragDrop<number>) {\r\n moveItemInArray(this.assets, event.previousContainer.data, event.container.data);\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n}\r\n","<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","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ContentChild,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n SimpleChanges,\r\n TemplateRef,\r\n} from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { DataService, GetCollectionContentsQuery } from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n startWith,\r\n switchMap,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-collection-contents',\r\n templateUrl: './collection-contents.component.html',\r\n styleUrls: ['./collection-contents.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionContentsComponent implements OnInit, OnChanges, OnDestroy {\r\n @Input() collectionId: string;\r\n @ContentChild(TemplateRef, { static: true }) headerTemplate: TemplateRef<any>;\r\n\r\n contents$: Observable<NonNullable<GetCollectionContentsQuery['collection']>['productVariants']['items']>;\r\n contentsTotalItems$: Observable<number>;\r\n contentsItemsPerPage$: Observable<number>;\r\n contentsCurrentPage$: Observable<number>;\r\n filterTermControl = new FormControl('');\r\n private collectionIdChange$ = new BehaviorSubject<string>('');\r\n private refresh$ = new BehaviorSubject<boolean>(true);\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(private route: ActivatedRoute, private router: Router, private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.contentsCurrentPage$ = this.route.paramMap.pipe(\r\n map(qpm => qpm.get('contentsPage')),\r\n map(page => (!page ? 1 : +page)),\r\n startWith(1),\r\n distinctUntilChanged(),\r\n );\r\n\r\n this.contentsItemsPerPage$ = this.route.paramMap.pipe(\r\n map(qpm => qpm.get('contentsPerPage')),\r\n map(perPage => (!perPage ? 10 : +perPage)),\r\n startWith(10),\r\n distinctUntilChanged(),\r\n );\r\n\r\n const filterTerm$ = this.filterTermControl.valueChanges.pipe(\r\n debounceTime(250),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(''),\r\n );\r\n\r\n const collection$ = combineLatest(\r\n this.collectionIdChange$,\r\n this.contentsCurrentPage$,\r\n this.contentsItemsPerPage$,\r\n filterTerm$,\r\n this.refresh$,\r\n ).pipe(\r\n takeUntil(this.destroy$),\r\n switchMap(([id, currentPage, itemsPerPage, filterTerm]) => {\r\n const take = itemsPerPage;\r\n const skip = (currentPage - 1) * itemsPerPage;\r\n if (id) {\r\n return this.dataService.collection\r\n .getCollectionContents(id, take, skip, filterTerm)\r\n .mapSingle(data => data.collection);\r\n } else {\r\n return of(null);\r\n }\r\n }),\r\n );\r\n\r\n this.contents$ = collection$.pipe(map(result => (result ? result.productVariants.items : [])));\r\n this.contentsTotalItems$ = collection$.pipe(\r\n map(result => (result ? result.productVariants.totalItems : 0)),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('collectionId' in changes) {\r\n this.collectionIdChange$.next(changes.collectionId.currentValue);\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy$.next();\r\n this.destroy$.complete();\r\n }\r\n\r\n setContentsPageNumber(page: number) {\r\n this.setParam('contentsPage', page);\r\n }\r\n\r\n setContentsItemsPerPage(perPage: number) {\r\n this.setParam('contentsPerPage', perPage);\r\n }\r\n\r\n refresh() {\r\n this.refresh$.next(true);\r\n }\r\n\r\n private setParam(key: string, value: any) {\r\n this.router.navigate(['./', { ...this.route.snapshot.params, [key]: value }], {\r\n relativeTo: this.route,\r\n queryParamsHandling: 'merge',\r\n });\r\n }\r\n}\r\n","<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\">\r\n <div class=\"clr-col\">\r\n <label>{{ 'catalog.filters' | translate }}</label>\r\n <vdr-form-field [label]=\"'catalog.filter-inheritance' | translate\" for=\"inheritFilters\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n formControlName=\"inheritFilters\"\r\n id=\"inheritFilters\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.inheritFilters; else noInherit\">{{\r\n 'catalog.inherit-filters-from-parent' | translate\r\n }}</ng-container>\r\n <ng-template #noInherit>{{\r\n 'catalog.do-not-inherit-filters' | translate\r\n }}</ng-template>\r\n </label>\r\n </clr-toggle-wrapper>\r\n </vdr-form-field>\r\n <div formArrayName=\"filters\">\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 </div>\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","import {\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n OnDestroy,\n OnInit,\n ViewChild,\n} from '@angular/core';\nimport { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\nimport {\n Asset,\n BaseDetailComponent,\n Collection,\n CollectionFragment,\n ConfigurableOperation,\n ConfigurableOperationDefinition,\n ConfigurableOperationInput,\n CreateCollectionInput,\n createUpdatedTranslatable,\n CustomFieldConfig,\n DataService,\n encodeConfigArgValue,\n findTranslation,\n getConfigArgValue,\n LanguageCode,\n ModalService,\n NotificationService,\n Permission,\n ServerConfigService,\n unicodePatternValidator,\n UpdateCollectionInput,\n} from '@vendure/admin-ui/core';\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\nimport { combineLatest } from 'rxjs';\nimport { mergeMap, take } from 'rxjs/operators';\n\nimport { CollectionContentsComponent } from '../collection-contents/collection-contents.component';\n\n@Component({\n selector: 'vdr-collection-detail',\n templateUrl: './collection-detail.component.html',\n styleUrls: ['./collection-detail.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CollectionDetailComponent\n extends BaseDetailComponent<CollectionFragment>\n implements OnInit, OnDestroy\n{\n customFields: CustomFieldConfig[];\n detailForm: FormGroup;\n assetChanges: { assets?: Asset[]; featuredAsset?: Asset } = {};\n filters: ConfigurableOperation[] = [];\n allFilters: ConfigurableOperationDefinition[] = [];\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];\n @ViewChild('collectionContents') contentsComponent: CollectionContentsComponent;\n\n constructor(\n router: Router,\n route: ActivatedRoute,\n serverConfigService: ServerConfigService,\n private changeDetector: ChangeDetectorRef,\n protected dataService: DataService,\n private formBuilder: FormBuilder,\n private notificationService: NotificationService,\n private modalService: ModalService,\n ) {\n super(route, router, serverConfigService, dataService);\n this.customFields = this.getCustomFieldConfig('Collection');\n this.detailForm = this.formBuilder.group({\n name: ['', Validators.required],\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\n description: '',\n visible: false,\n inheritFilters: true,\n filters: this.formBuilder.array([]),\n customFields: this.formBuilder.group(\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\n ),\n });\n }\n\n ngOnInit() {\n this.init();\n this.dataService.collection.getCollectionFilters().single$.subscribe(res => {\n this.allFilters = res.collectionFilters;\n });\n }\n\n ngOnDestroy() {\n this.destroy();\n }\n\n getFilterDefinition(filter: ConfigurableOperation): ConfigurableOperationDefinition | undefined {\n return this.allFilters.find(f => f.code === filter.code);\n }\n\n assetsChanged(): boolean {\n return !!Object.values(this.assetChanges).length;\n }\n\n /**\n * If creating a new Collection, automatically generate the slug based on the collection name.\n */\n updateSlug(nameValue: string) {\n combineLatest(this.entity$, this.languageCode$)\n .pipe(take(1))\n .subscribe(([entity, languageCode]) => {\n const slugControl = this.detailForm.get(['slug']);\n const currentTranslation = findTranslation(entity, languageCode);\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\n }\n });\n }\n\n addFilter(collectionFilter: ConfigurableOperation) {\n const filtersArray = this.detailForm.get('filters') as FormArray;\n const index = filtersArray.value.findIndex(o => o.code === collectionFilter.code);\n if (index === -1) {\n const argsHash = collectionFilter.args.reduce(\n (output, arg) => ({\n ...output,\n [arg.name]: getConfigArgValue(arg.value),\n }),\n {},\n );\n filtersArray.push(\n this.formBuilder.control({\n code: collectionFilter.code,\n args: argsHash,\n }),\n );\n this.filters.push({\n code: collectionFilter.code,\n args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),\n });\n }\n }\n\n removeFilter(collectionFilter: ConfigurableOperation) {\n const filtersArray = this.detailForm.get('filters') as FormArray;\n const index = filtersArray.value.findIndex(o => o.code === collectionFilter.code);\n if (index !== -1) {\n filtersArray.removeAt(index);\n this.filters.splice(index, 1);\n }\n }\n\n create() {\n if (!this.detailForm.dirty) {\n return;\n }\n combineLatest(this.entity$, this.languageCode$)\n .pipe(\n take(1),\n mergeMap(([category, languageCode]) => {\n const input = this.getUpdatedCollection(\n category,\n this.detailForm,\n languageCode,\n ) as CreateCollectionInput;\n const parentId = this.route.snapshot.paramMap.get('parentId');\n if (parentId) {\n input.parentId = parentId;\n }\n return this.dataService.collection.createCollection(input);\n }),\n )\n .subscribe(\n data => {\n this.notificationService.success(_('common.notify-create-success'), {\n entity: 'Collection',\n });\n this.assetChanges = {};\n this.detailForm.markAsPristine();\n this.changeDetector.markForCheck();\n this.router.navigate(['../', data.createCollection.id], { relativeTo: this.route });\n },\n err => {\n this.notificationService.error(_('common.notify-create-error'), {\n entity: 'Collection',\n });\n },\n );\n }\n\n save() {\n combineLatest(this.entity$, this.languageCode$)\n .pipe(\n take(1),\n mergeMap(([category, languageCode]) => {\n const input = this.getUpdatedCollection(\n category,\n this.detailForm,\n languageCode,\n ) as UpdateCollectionInput;\n return this.dataService.collection.updateCollection(input);\n }),\n )\n .subscribe(\n () => {\n this.assetChanges = {};\n this.detailForm.markAsPristine();\n this.changeDetector.markForCheck();\n this.notificationService.success(_('common.notify-update-success'), {\n entity: 'Collection',\n });\n this.contentsComponent.refresh();\n },\n err => {\n this.notificationService.error(_('common.notify-update-error'), {\n entity: 'Collection',\n });\n },\n );\n }\n\n canDeactivate(): boolean {\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\n }\n\n /**\n * Sets the values of the form on changes to the category or current language.\n */\n protected setFormValues(entity: CollectionFragment, languageCode: LanguageCode) {\n const currentTranslation = findTranslation(entity, languageCode);\n\n this.detailForm.patchValue({\n name: currentTranslation ? currentTranslation.name : '',\n slug: currentTranslation ? currentTranslation.slug : '',\n description: currentTranslation ? currentTranslation.description : '',\n visible: !entity.isPrivate,\n inheritFilters: entity.inheritFilters,\n });\n\n entity.filters.forEach(f => this.addFilter(f));\n\n if (this.customFields.length) {\n this.setCustomFieldFormValues(\n this.customFields,\n this.detailForm.get(['customFields']),\n entity,\n currentTranslation,\n );\n }\n }\n\n /**\n * Given a category and the value of the form, this method creates an updated copy of the category which\n * can then be persisted to the API.\n */\n private getUpdatedCollection(\n category: CollectionFragment,\n form: FormGroup,\n languageCode: LanguageCode,\n ): CreateCollectionInput | UpdateCollectionInput {\n const updatedCategory = createUpdatedTranslatable({\n translatable: category,\n updatedFields: form.value,\n customFieldConfig: this.customFields,\n languageCode,\n defaultTranslation: {\n languageCode,\n name: category.name || '',\n slug: category.slug || '',\n description: category.description || '',\n },\n });\n return {\n ...updatedCategory,\n assetIds: this.assetChanges.assets?.map(a => a.id),\n featuredAssetId: this.assetChanges.featuredAsset?.id,\n isPrivate: !form.value.visible,\n filters: this.mapOperationsToInputs(this.filters, this.detailForm.value.filters),\n };\n }\n\n /**\n * Maps an array of conditions or actions to the input format expected by the GraphQL API.\n */\n private mapOperationsToInputs(\n operations: ConfigurableOperation[],\n formValueOperations: any,\n ): ConfigurableOperationInput[] {\n return operations.map((o, i) => {\n return {\n code: o.code,\n arguments: Object.values(formValueOperations[i].args).map((value: any, j) => ({\n name: o.args[j].name,\n value: encodeConfigArgValue(value),\n })),\n };\n });\n }\n}\n","export type HasParent = { id: string; parent?: { id: string } | null };\nexport type TreeNode<T extends HasParent> = T & { children: Array<TreeNode<T>>; expanded: boolean };\nexport type RootNode<T extends HasParent> = { id?: string; children: Array<TreeNode<T>> };\n\n/**\n * Builds a tree from an array of nodes which have a parent.\n * Based on https://stackoverflow.com/a/31247960/772859, modified to preserve ordering.\n */\nexport function arrayToTree<T extends HasParent>(nodes: T[], currentState?: RootNode<T>): RootNode<T> {\n const topLevelNodes: Array<TreeNode<T>> = [];\n const mappedArr: { [id: string]: TreeNode<T> } = {};\n const currentStateMap = treeToMap(currentState);\n\n // First map the nodes of the array to an object -> create a hash table.\n for (const node of nodes) {\n mappedArr[node.id] = { ...(node as any), children: [] };\n }\n\n for (const id of nodes.map(n => n.id)) {\n if (mappedArr.hasOwnProperty(id)) {\n const mappedElem = mappedArr[id];\n mappedElem.expanded = currentStateMap.get(id)?.expanded ?? false;\n const parent = mappedElem.parent;\n if (!parent) {\n continue;\n }\n // If the element is not at the root level, add it to its parent array of children.\n const parentIsRoot = !mappedArr[parent.id];\n if (!parentIsRoot) {\n if (mappedArr[parent.id]) {\n mappedArr[parent.id].children.push(mappedElem);\n } else {\n mappedArr[parent.id] = { children: [mappedElem] } as any;\n }\n } else {\n topLevelNodes.push(mappedElem);\n }\n }\n }\n // tslint:disable-next-line:no-non-null-assertion\n const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined;\n return { id: rootId, children: topLevelNodes };\n}\n\n/**\n * Converts an existing tree (as generated by the arrayToTree function) into a flat\n * Map. This is used to persist certain states (e.g. `expanded`) when re-building the\n * tree.\n */\nfunction treeToMap<T extends HasParent>(tree?: RootNode<T>): Map<string, TreeNode<T>> {\n const nodeMap = new Map<string, TreeNode<T>>();\n function visit(node: TreeNode<T>) {\n nodeMap.set(node.id, node);\n node.children.forEach(visit);\n }\n if (tree) {\n visit(tree as TreeNode<T>);\n }\n return nodeMap;\n}\n","import { CdkDragDrop } from '@angular/cdk/drag-drop';\r\nimport { Injectable, OnDestroy } from '@angular/core';\r\nimport { Observable, Subject } from 'rxjs';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n/**\r\n * Facilitates communication between the CollectionTreeComponent and child CollectionTreeNodeComponents\r\n * without introducing a cyclic dependency.\r\n */\r\n@Injectable()\r\nexport class CollectionTreeService implements OnDestroy {\r\n private allMoveListItems: Array<{ path: string; id: string; ancestorIdPath: Set<string> }> = [];\r\n private collectionTree: RootNode<CollectionPartial>;\r\n private _rearrange$ = new Subject<RearrangeEvent>();\r\n private _delete$ = new Subject<string>();\r\n\r\n public rearrange$: Observable<RearrangeEvent>;\r\n public delete$: Observable<string>;\r\n\r\n constructor() {\r\n this.rearrange$ = this._rearrange$.asObservable();\r\n this.delete$ = this._delete$.asObservable();\r\n }\r\n\r\n ngOnDestroy() {\r\n this._rearrange$.complete();\r\n this._delete$.complete();\r\n }\r\n\r\n setCollectionTree(tree: RootNode<CollectionPartial>) {\r\n this.collectionTree = tree;\r\n }\r\n\r\n resetMoveList() {\r\n this.allMoveListItems = [];\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n if (this.allMoveListItems.length === 0) {\r\n this.allMoveListItems = this.calculateAllMoveListItems();\r\n }\r\n return this.allMoveListItems.filter(\r\n item =>\r\n item.id !== collection.id &&\r\n !item.ancestorIdPath.has(collection.id) &&\r\n item.id !== collection.parent?.id,\r\n );\r\n }\r\n\r\n onDrop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n const item = event.item.data as CollectionPartial;\r\n const newParent = event.container.data;\r\n const newParentId = newParent.id;\r\n if (newParentId == null) {\r\n throw new Error(`Could not determine the ID of the root Collection`);\r\n }\r\n this._rearrange$.next({\r\n collectionId: item.id,\r\n parentId: newParentId,\r\n index: event.currentIndex,\r\n });\r\n }\r\n\r\n onMove(event: RearrangeEvent) {\r\n this._rearrange$.next(event);\r\n }\r\n\r\n onDelete(id: string) {\r\n this._delete$.next(id);\r\n }\r\n\r\n private calculateAllMoveListItems() {\r\n const visit = (\r\n node: TreeNode<any>,\r\n parentPath: string[],\r\n ancestorIdPath: Set<string>,\r\n output: Array<{ path: string; id: string; ancestorIdPath: Set<string> }>,\r\n ) => {\r\n const path = parentPath.concat(node.name);\r\n output.push({ path: path.slice(1).join(' / ') || 'root', id: node.id, ancestorIdPath });\r\n node.children.forEach(child =>\r\n visit(child, path, new Set<string>([...ancestorIdPath, node.id]), output),\r\n );\r\n return output;\r\n };\r\n return visit(this.collectionTree, [], new Set<string>(), []);\r\n }\r\n}\r\n","<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","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n Component,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Optional,\r\n SimpleChanges,\r\n SkipSelf,\r\n} from '@angular/core';\r\nimport { DataService, Permission } from '@vendure/admin-ui/core';\r\nimport { Observable } from 'rxjs';\r\nimport { map, shareReplay } from 'rxjs/operators';\r\n\r\nimport { RootNode, TreeNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree-node',\r\n templateUrl: './collection-tree-node.component.html',\r\n styleUrls: ['./collection-tree-node.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionTreeNodeComponent implements OnInit, OnChanges {\r\n depth = 0;\r\n parentName: string;\r\n @Input() collectionTree: TreeNode<CollectionPartial>;\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n hasUpdatePermission$: Observable<boolean>;\r\n hasDeletePermission$: Observable<boolean>;\r\n moveListItems: Array<{ path: string; id: string }> = [];\r\n\r\n constructor(\r\n @SkipSelf() @Optional() private parent: CollectionTreeNodeComponent,\r\n private dataService: DataService,\r\n private collectionTreeService: CollectionTreeService,\r\n ) {\r\n if (parent) {\r\n this.depth = parent.depth + 1;\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.parentName = this.collectionTree.name || '<root>';\r\n const permissions$ = this.dataService.client\r\n .userStatus()\r\n .mapStream(data => data.userStatus.permissions)\r\n .pipe(shareReplay(1));\r\n this.hasUpdatePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.UpdateCatalog) || perms.includes(Permission.UpdateCollection),\r\n ),\r\n );\r\n this.hasDeletePermission$ = permissions$.pipe(\r\n map(\r\n perms =>\r\n perms.includes(Permission.DeleteCatalog) || perms.includes(Permission.DeleteCollection),\r\n ),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n const expandAllChange = changes['expandAll'];\r\n if (expandAllChange) {\r\n if (expandAllChange.previousValue === true && expandAllChange.currentValue === false) {\r\n this.collectionTree.children.forEach(c => (c.expanded = false));\r\n }\r\n }\r\n }\r\n\r\n trackByFn(index: number, item: CollectionPartial) {\r\n return item.id;\r\n }\r\n\r\n getMoveListItems(collection: CollectionPartial) {\r\n this.moveListItems = this.collectionTreeService.getMoveListItems(collection);\r\n }\r\n\r\n move(collection: CollectionPartial, parentId: string) {\r\n this.collectionTreeService.onMove({\r\n index: 0,\r\n parentId,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveUp(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex - 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n moveDown(collection: CollectionPartial, currentIndex: number) {\r\n if (!collection.parent) {\r\n return;\r\n }\r\n this.collectionTreeService.onMove({\r\n index: currentIndex + 1,\r\n parentId: collection.parent.id,\r\n collectionId: collection.id,\r\n });\r\n }\r\n\r\n drop(event: CdkDragDrop<CollectionPartial | RootNode<CollectionPartial>>) {\r\n moveItemInArray(this.collectionTree.children, event.previousIndex, event.currentIndex);\r\n this.collectionTreeService.onDrop(event);\r\n }\r\n\r\n delete(id: string) {\r\n this.collectionTreeService.onDelete(id);\r\n }\r\n}\r\n","<vdr-collection-tree-node\r\n *ngIf=\"collectionTree\"\r\n cdkDropListGroup\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collectionTree\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n></vdr-collection-tree-node>\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n} from '@angular/core';\r\n\r\nimport { arrayToTree, RootNode } from './array-to-tree';\r\nimport { CollectionTreeService } from './collection-tree.service';\r\nimport { CollectionPartial, RearrangeEvent } from './collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-tree',\r\n templateUrl: 'collection-tree.component.html',\r\n styleUrls: ['./collection-tree.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [CollectionTreeService],\r\n})\r\nexport class CollectionTreeComponent implements OnInit, OnChanges {\r\n @Input() collections: CollectionPartial[];\r\n @Input() activeCollectionId: string;\r\n @Input() expandAll = false;\r\n @Output() rearrange = new EventEmitter<RearrangeEvent>();\r\n @Output() deleteCollection = new EventEmitter<string>();\r\n collectionTree: RootNode<CollectionPartial>;\r\n\r\n constructor(private collectionTreeService: CollectionTreeService) {}\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n if ('collections' in changes && this.collections) {\r\n this.collectionTree = arrayToTree(this.collections, this.collectionTree);\r\n this.collectionTreeService.setCollectionTree(this.collectionTree);\r\n this.collectionTreeService.resetMoveList();\r\n }\r\n }\r\n\r\n ngOnInit() {\r\n this.collectionTreeService.rearrange$.subscribe(event => this.rearrange.emit(event));\r\n this.collectionTreeService.delete$.subscribe(id => this.deleteCollection.emit(id));\r\n }\r\n}\r\n","<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","import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n GetCollectionListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n QueryResult,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, EMPTY, Observable, Subject } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n shareReplay,\r\n switchMap,\r\n take,\r\n takeUntil,\r\n tap,\r\n} from 'rxjs/operators';\r\n\r\nimport { RearrangeEvent } from '../collection-tree/collection-tree.types';\r\n\r\n@Component({\r\n selector: 'vdr-collection-list',\r\n templateUrl: './collection-list.component.html',\r\n styleUrls: ['./collection-list.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionListComponent implements OnInit, OnDestroy {\r\n filterTermControl = new FormControl('');\r\n activeCollectionId$: Observable<string | null>;\r\n activeCollectionTitle$: Observable<string>;\r\n items$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n expandAll = false;\r\n private queryResult: QueryResult<any>;\r\n private destroy$ = new Subject<void>();\r\n\r\n constructor(\r\n private dataService: DataService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private router: Router,\r\n private route: ActivatedRoute,\r\n private serverConfigService: ServerConfigService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.queryResult = this.dataService.collection.getCollections(1000, 0).refetchOnChannelChange();\r\n this.items$ = this.queryResult.mapStream(data => data.collections.items).pipe(shareReplay(1));\r\n this.activeCollectionId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('contents')),\r\n distinctUntilChanged(),\r\n );\r\n\r\n this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(\r\n map(([id, collections]) => {\r\n if (id) {\r\n const match = collections.find(c => c.id === id);\r\n return match ? match.name : '';\r\n }\r\n return '';\r\n }),\r\n );\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.filterTermControl.valueChanges\r\n .pipe(debounceTime(250), takeUntil(this.destroy$))\r\n .subscribe(() => this.refresh());\r\n }\r\n\r\n ngOnDestroy() {\r\n this.queryResult.completed$.next();\r\n this.destroy$.next(undefined);\r\n this.destroy$.complete();\r\n }\r\n\r\n onRearrange(event: RearrangeEvent) {\r\n this.dataService.collection.moveCollection([event]).subscribe({\r\n next: () => {\r\n this.notificationService.success(_('common.notify-saved-changes'));\r\n this.refresh();\r\n },\r\n error: err => {\r\n this.notificationService.error(_('common.notify-save-changes-error'));\r\n },\r\n });\r\n }\r\n\r\n deleteCollection(id: string) {\r\n this.items$\r\n .pipe(\r\n take(1),\r\n map(items => -1 < items.findIndex(i => i.parent && i.parent.id === id)),\r\n switchMap(hasChildren => {\r\n return this.modalService.dialog({\r\n title: _('catalog.confirm-delete-collection'),\r\n body: hasChildren\r\n ? _('catalog.confirm-delete-collection-and-children-body')\r\n : undefined,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n });\r\n }),\r\n switchMap(response => (response ? this.dataService.collection.deleteCollection(id) : EMPTY)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Collection',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Collection',\r\n });\r\n },\r\n );\r\n }\r\n\r\n closeContents() {\r\n const params = { ...this.route.snapshot.params };\r\n delete params.contents;\r\n this.router.navigate(['./', params], { relativeTo: this.route, queryParamsHandling: 'preserve' });\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n private refresh() {\r\n this.queryResult.ref.refetch({\r\n options: {\r\n skip: 0,\r\n take: 1000,\r\n ...(this.filterTermControl.value\r\n ? {\r\n filter: {\r\n name: {\r\n contains: this.filterTermControl.value,\r\n },\r\n },\r\n }\r\n : {}),\r\n },\r\n });\r\n }\r\n}\r\n","<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=\"facet-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\"\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 facet\">\r\n <section class=\"form-block\" formGroupName=\"facet\">\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 [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"visible\"\r\n id=\"visibility\"\r\n />\r\n <label class=\"visible-toggle\">\r\n <ng-container *ngIf=\"detailForm.value.facet.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)=\"updateCode(facet.code, $event.target.value)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field\r\n [label]=\"'common.code' | translate\"\r\n for=\"code\"\r\n [readOnlyToggle]=\"updatePermission | hasPermission\"\r\n >\r\n <input\r\n id=\"code\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\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=\"Facet\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"detailForm.get(['facet', '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=\"facet-detail\"\r\n [entity$]=\"entity$\"\r\n [detailForm]=\"detailForm\"\r\n ></vdr-custom-detail-component-host>\r\n </section>\r\n\r\n <section class=\"form-block\" *ngIf=\"!(isNew$ | async)\">\r\n <label>{{ 'catalog.facet-values' | translate }}</label>\r\n\r\n <table class=\"facet-values-list table\" formArrayName=\"values\" *ngIf=\"0 < getValuesFormArray().length\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n <ng-container *ngIf=\"customValueFields.length\">\r\n <th>{{ 'common.custom-fields' | translate }}</th>\r\n </ng-container>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr class=\"facet-value\" *ngFor=\"let value of values; let i = index\" [formGroupName]=\"i\">\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n (input)=\"updateValueCode(facet.values[i]?.code, $event.target.value, i)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" readonly /></td>\r\n <td class=\"\" *ngIf=\"customValueFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"FacetValue\"\r\n [customFields]=\"customValueFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"detailForm.get(['values', i, 'customFields'])\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </td>\r\n <td class=\"align-middle\">\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)=\"deleteFacetValue(facet.values[i]?.id, i)\"\r\n [disabled]=\"!(updatePermission | 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 </tr>\r\n </tbody>\r\n </table>\r\n\r\n <div>\r\n <button\r\n type=\"button\"\r\n class=\"btn btn-secondary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n (click)=\"addFacetValue()\"\r\n >\r\n <clr-icon shape=\"add\"></clr-icon>\r\n {{ 'catalog.add-facet-value' | translate }}\r\n </button>\r\n </div>\r\n </section>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n CreateFacetInput,\r\n CreateFacetValueInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n UpdateFacetInput,\r\n UpdateFacetValueInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { combineLatest, EMPTY, forkJoin, Observable } from 'rxjs';\r\nimport { map, mapTo, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-detail',\r\n templateUrl: './facet-detail.component.html',\r\n styleUrls: ['./facet-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class FacetDetailComponent\r\n extends BaseDetailComponent<FacetWithValuesFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n customValueFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n values: Array<FacetWithValuesFragment['values'][number] | { name: string; code: string }>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateFacet];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private changeDetector: ChangeDetectorRef,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Facet');\r\n this.customValueFields = this.getCustomFieldConfig('FacetValue');\r\n this.detailForm = this.formBuilder.group({\r\n facet: this.formBuilder.group({\r\n code: ['', Validators.required],\r\n name: '',\r\n visible: true,\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n }),\r\n values: this.formBuilder.array([]),\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n updateCode(currentCode: string, nameValue: string) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['facet', 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n updateValueCode(currentCode: string, nameValue: string, index: number) {\r\n if (!currentCode) {\r\n const codeControl = this.detailForm.get(['values', index, 'code']);\r\n if (codeControl && codeControl.pristine) {\r\n codeControl.setValue(normalizeString(nameValue, '-'));\r\n }\r\n }\r\n }\r\n\r\n customValueFieldIsSet(index: number, name: string): boolean {\r\n return !!this.detailForm.get(['values', index, 'customFields', name]);\r\n }\r\n\r\n getValuesFormArray(): FormArray {\r\n return this.detailForm.get('values') as FormArray;\r\n }\r\n\r\n addFacetValue() {\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n const valueGroup = this.formBuilder.group({\r\n id: '',\r\n name: ['', Validators.required],\r\n code: '',\r\n });\r\n const newValue: any = { name: '', code: '' };\r\n if (this.customValueFields.length) {\r\n const customValueFieldsGroup = new FormGroup({});\r\n newValue.customFields = {};\r\n\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n customValueFieldsGroup.addControl(key, new FormControl());\r\n }\r\n\r\n valueGroup.addControl('customFields', customValueFieldsGroup);\r\n }\r\n valuesFormArray.insert(valuesFormArray.length, valueGroup);\r\n this.values.push(newValue);\r\n }\r\n }\r\n\r\n create() {\r\n const facetForm = this.detailForm.get('facet');\r\n if (!facetForm || !facetForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetForm as FormGroup,\r\n languageCode,\r\n ) as CreateFacetInput;\r\n return this.dataService.facet.createFacet(newFacet);\r\n }),\r\n switchMap(data => this.dataService.facet.getAllFacets().single$.pipe(mapTo(data))),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), { entity: 'Facet' });\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createFacet.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([facet, languageCode]) => {\r\n const facetGroup = this.detailForm.get('facet');\r\n const updateOperations: Array<Observable<any>> = [];\r\n\r\n if (facetGroup && facetGroup.dirty) {\r\n const newFacet = this.getUpdatedFacet(\r\n facet,\r\n facetGroup as FormGroup,\r\n languageCode,\r\n ) as UpdateFacetInput;\r\n if (newFacet) {\r\n updateOperations.push(this.dataService.facet.updateFacet(newFacet));\r\n }\r\n }\r\n const valuesArray = this.detailForm.get('values');\r\n if (valuesArray && valuesArray.dirty) {\r\n const createdValues = this.getCreatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (createdValues.length) {\r\n updateOperations.push(\r\n this.dataService.facet\r\n .createFacetValues(createdValues)\r\n .pipe(switchMap(() => this.dataService.facet.getFacet(this.id).single$)),\r\n );\r\n }\r\n const updatedValues = this.getUpdatedFacetValues(\r\n facet,\r\n valuesArray as FormArray,\r\n languageCode,\r\n );\r\n if (updatedValues.length) {\r\n updateOperations.push(this.dataService.facet.updateFacetValues(updatedValues));\r\n }\r\n }\r\n\r\n return forkJoin(updateOperations);\r\n }),\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Facet' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Facet',\r\n });\r\n },\r\n );\r\n }\r\n\r\n deleteFacetValue(facetValueId: string | undefined, index: number) {\r\n if (!facetValueId) {\r\n // deleting a newly-added (not persisted) FacetValue\r\n const valuesFormArray = this.detailForm.get('values') as FormArray | null;\r\n if (valuesFormArray) {\r\n valuesFormArray.removeAt(index);\r\n }\r\n this.values.splice(index, 1);\r\n return;\r\n }\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n switchMap(deleted => (deleted ? this.dataService.facet.getFacet(this.id).single$ : [])),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(facetValueId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet-value'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(result =>\r\n result ? this.dataService.facet.deleteFacetValues([facetValueId], !!message) : EMPTY,\r\n ),\r\n map(result => result.deleteFacetValues[0]),\r\n );\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the facet or current language.\r\n */\r\n protected setFormValues(facet: FacetWithValuesFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(facet, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n facet: {\r\n code: facet.code,\r\n visible: !facet.isPrivate,\r\n name: currentTranslation?.name ?? '',\r\n },\r\n });\r\n\r\n if (this.customFields.length) {\r\n const customFieldsGroup = this.detailForm.get(['facet', 'customFields']) as FormGroup;\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['facet', 'customFields']),\r\n facet,\r\n currentTranslation,\r\n );\r\n }\r\n\r\n const currentValuesFormArray = this.detailForm.get('values') as FormArray;\r\n this.values = [...facet.values];\r\n facet.values.forEach((value, i) => {\r\n const valueTranslation = findTranslation(value, languageCode);\r\n const group = {\r\n id: value.id,\r\n code: value.code,\r\n name: valueTranslation ? valueTranslation.name : '',\r\n };\r\n const valueControl = currentValuesFormArray.at(i);\r\n if (valueControl) {\r\n valueControl.get('id')?.setValue(group.id);\r\n valueControl.get('code')?.setValue(group.code);\r\n valueControl.get('name')?.setValue(group.name);\r\n } else {\r\n currentValuesFormArray.insert(i, this.formBuilder.group(group));\r\n }\r\n if (this.customValueFields.length) {\r\n let customValueFieldsGroup = this.detailForm.get(['values', i, 'customFields']) as FormGroup;\r\n if (!customValueFieldsGroup) {\r\n customValueFieldsGroup = new FormGroup({});\r\n (this.detailForm.get(['values', i]) as FormGroup).addControl(\r\n 'customFields',\r\n customValueFieldsGroup,\r\n );\r\n }\r\n\r\n if (customValueFieldsGroup) {\r\n for (const fieldDef of this.customValueFields) {\r\n const key = fieldDef.name;\r\n const fieldValue =\r\n fieldDef.type === 'localeString'\r\n ? (valueTranslation as any).customFields[key]\r\n : (value as any).customFields[key];\r\n const control = customValueFieldsGroup.get(key);\r\n if (control) {\r\n control.setValue(fieldValue);\r\n } else {\r\n customValueFieldsGroup.addControl(key, new FormControl(fieldValue));\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Given a facet and the value of the detailForm, this method creates an updated copy of the facet which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedFacet(\r\n facet: FacetWithValuesFragment,\r\n facetFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateFacetInput | UpdateFacetInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: facet,\r\n updatedFields: facetFormGroup.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: facet.name || '',\r\n },\r\n });\r\n input.isPrivate = !facetFormGroup.value.visible;\r\n return input;\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via a createFacetValues mutation.\r\n */\r\n private getCreatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): CreateFacetValueInput[] {\r\n return valuesFormArray.controls\r\n .filter(c => !c.value.id)\r\n .map(c => c.value)\r\n .map(value =>\r\n createUpdatedTranslatable({\r\n translatable: { ...value, translations: [] as any },\r\n updatedFields: value,\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n }),\r\n )\r\n .map(input => ({\r\n facetId: facet.id,\r\n ...input,\r\n }));\r\n }\r\n\r\n /**\r\n * Given an array of facet values and the values from the detailForm, this method creates a new array\r\n * which can be persisted to the API via an updateFacetValues mutation.\r\n */\r\n private getUpdatedFacetValues(\r\n facet: FacetWithValuesFragment,\r\n valuesFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n ): UpdateFacetValueInput[] {\r\n const dirtyValues = facet.values.filter((v, i) => {\r\n const formRow = valuesFormArray.get(i.toString());\r\n return formRow && formRow.dirty && formRow.value.id;\r\n });\r\n const dirtyValueValues = valuesFormArray.controls\r\n .filter(c => c.dirty && c.value.id)\r\n .map(c => c.value);\r\n\r\n if (dirtyValues.length !== dirtyValueValues.length) {\r\n throw new Error(_(`error.facet-value-form-values-do-not-match`));\r\n }\r\n return dirtyValues\r\n .map((value, i) => {\r\n return createUpdatedTranslatable({\r\n translatable: value,\r\n updatedFields: dirtyValueValues[i],\r\n customFieldConfig: this.customValueFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n });\r\n })\r\n .filter(notNullOrUndefined);\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <div class=\"flex center wrap\">\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 <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=\"facet-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateFacet']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-facet' | translate }}\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 <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'common.name' | translate }}</vdr-dt-column>\r\n <vdr-dt-column [expand]=\"true\">{{ 'catalog.values' | translate }}</vdr-dt-column>\r\n <vdr-dt-column>{{ 'catalog.visibility' | translate }}</vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <vdr-dt-column></vdr-dt-column>\r\n <ng-template let-facet=\"item\">\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.code }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">{{ facet.name }}</td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let value of facet.values | slice: 0:displayLimit[facet.id] || 3\"\r\n [facetValue]=\"value\"\r\n [removable]=\"false\"\r\n [displayFacetName]=\"false\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n class=\"btn btn-sm btn-secondary btn-icon\"\r\n *ngIf=\"facet.values.length > initialLimit\"\r\n (click)=\"toggleDisplayLimit(facet)\"\r\n >\r\n <ng-container *ngIf=\"(displayLimit[facet.id] || 0) < facet.values.length; else collapse\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ facet.values.length - initialLimit }}\r\n </ng-container>\r\n <ng-template #collapse>\r\n <clr-icon shape=\"minus\"></clr-icon>\r\n </ng-template>\r\n </button>\r\n </td>\r\n <td class=\"left align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-chip>\r\n <ng-container *ngIf=\"!facet.isPrivate; else private\">{{\r\n 'catalog.public' | translate\r\n }}</ng-container>\r\n <ng-template #private>{{ 'catalog.private' | translate }}</ng-template>\r\n </vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', facet.id]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n <td class=\"right align-middle\" [class.private]=\"facet.isPrivate\">\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)=\"deleteFacet(facet.id)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteFacet'] | 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","import { Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetFacetListQuery,\r\n ItemOf,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { SortOrder } from '@vendure/common/lib/generated-shop-types';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-facet-list',\r\n templateUrl: './facet-list.component.html',\r\n styleUrls: ['./facet-list.component.scss'],\r\n})\r\nexport class FacetListComponent\r\n extends BaseListComponent<GetFacetListQuery, ItemOf<GetFacetListQuery, 'facets'>>\r\n implements OnInit\r\n{\r\n filterTermControl = new FormControl('');\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n readonly initialLimit = 3;\r\n displayLimit: { [id: string]: number } = {};\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.facet.getFacets(...args).refetchOnChannelChange(),\r\n data => data.facets,\r\n (skip, take) => ({\r\n options: {\r\n skip,\r\n take,\r\n filter: {\r\n name: {\r\n contains: this.filterTermControl.value,\r\n },\r\n },\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n },\r\n }),\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n this.filterTermControl.valueChanges\r\n .pipe(\r\n filter(value => 2 <= value.length || value.length === 0),\r\n debounceTime(250),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n }\r\n\r\n toggleDisplayLimit(facet: ItemOf<GetFacetListQuery, 'facets'>) {\r\n if (this.displayLimit[facet.id] === facet.values.length) {\r\n this.displayLimit[facet.id] = this.initialLimit;\r\n } else {\r\n this.displayLimit[facet.id] = facet.values.length;\r\n }\r\n }\r\n\r\n deleteFacet(facetValueId: string) {\r\n this.showModalAndDelete(facetValueId)\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(facetValueId, response.message || '').pipe(\r\n map(r => r.result === DeletionResult.DELETED),\r\n );\r\n }\r\n }),\r\n // Refresh the cached facets to reflect the changes\r\n switchMap(() => this.dataService.facet.getAllFacets().single$),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'FacetValue',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'FacetValue',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n\r\n private showModalAndDelete(facetId: string, message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-facet'),\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.facet.deleteFacet(facetId, !!message) : EMPTY)),\r\n map(res => res.deleteFacet),\r\n );\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.add-facets' | translate }}</ng-template>\r\n\r\n<vdr-facet-value-selector\r\n [facets]=\"facets\"\r\n (selectedValuesChange)=\"selectedValues = $event\"\r\n></vdr-facet-value-selector>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"selectValues()\"\r\n [disabled]=\"selectedValues.length === 0\"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n</ng-template>\r\n","import {\r\n AfterViewInit,\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport {\r\n Dialog,\r\n FacetValue,\r\n FacetValueSelectorComponent,\r\n FacetWithValuesFragment,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-apply-facet-dialog',\r\n templateUrl: './apply-facet-dialog.component.html',\r\n styleUrls: ['./apply-facet-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ApplyFacetDialogComponent implements Dialog<FacetValue[]>, AfterViewInit {\r\n @ViewChild(FacetValueSelectorComponent) private selector: FacetValueSelectorComponent;\r\n resolveWith: (result?: FacetValue[]) => void;\r\n selectedValues: FacetValue[] = [];\r\n // Provided by caller\r\n facets: FacetWithValuesFragment[];\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngAfterViewInit() {\r\n setTimeout(() => this.selector.focus(), 0);\r\n }\r\n\r\n selectValues() {\r\n this.resolveWith(this.selectedValues);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n <ng-container *ngIf=\"isProductVariantMode; else productModeTitle\">{{\r\n 'catalog.assign-variants-to-channel' | translate\r\n }}</ng-container>\r\n <ng-template #productModeTitle>{{ 'catalog.assign-products-to-channel' | translate }}</ng-template>\r\n</ng-template>\r\n\r\n<div class=\"flex\">\r\n <clr-input-container>\r\n <label>{{ 'common.channel' | translate }}</label>\r\n <vdr-channel-assignment-control\r\n clrInput\r\n [multiple]=\"false\"\r\n [includeDefaultChannel]=\"false\"\r\n [disableChannelIds]=\"currentChannelIds\"\r\n [formControl]=\"selectedChannelIdControl\"\r\n ></vdr-channel-assignment-control>\r\n </clr-input-container>\r\n <div class=\"flex-spacer\"></div>\r\n <clr-input-container>\r\n <label>{{ 'catalog.price-conversion-factor' | translate }}</label>\r\n <input clrInput type=\"number\" min=\"0\" max=\"99999\" [formControl]=\"priceFactorControl\" />\r\n </clr-input-container>\r\n</div>\r\n\r\n<div class=\"channel-price-preview\">\r\n <label class=\"clr-control-label\">{{ 'catalog.channel-price-preview' | translate }}</label>\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>\r\n {{\r\n 'catalog.price-in-channel'\r\n | translate: { channel: currentChannel?.code | channelCodeToLabel | translate }\r\n }}\r\n </th>\r\n <th>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.price-in-channel' | translate: { channel: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let row of variantsPreview$ | async\">\r\n <td>{{ row.name }}</td>\r\n <td>{{ row.price | localeCurrency: currentChannel?.currencyCode }}</td>\r\n <td>\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noChannelSelected\">\r\n {{ row.pricePreview | localeCurrency: selectedChannel?.currencyCode }}\r\n </ng-template>\r\n <ng-template #noChannelSelected> - </ng-template>\r\n </td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n</div>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"assign()\" [disabled]=\"!selectedChannel\" class=\"btn btn-primary\">\r\n <ng-template [ngIf]=\"selectedChannel\" [ngIfElse]=\"noSelection\">\r\n {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}\r\n </ng-template>\r\n <ng-template #noSelection>\r\n {{ 'catalog.no-channel-selected' | translate }}\r\n </ng-template>\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl } from '@angular/forms';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n DataService,\r\n Dialog,\r\n GetChannelsQuery,\r\n NotificationService,\r\n ProductVariantFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, from, Observable } from 'rxjs';\r\nimport { map, startWith } from 'rxjs/operators';\r\n\r\ntype Channel = GetChannelsQuery['channels'][number];\r\n\r\n@Component({\r\n selector: 'vdr-assign-products-to-channel-dialog',\r\n templateUrl: './assign-products-to-channel-dialog.component.html',\r\n styleUrls: ['./assign-products-to-channel-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssignProductsToChannelDialogComponent implements OnInit, Dialog<any> {\r\n selectedChannel: Channel | null | undefined;\r\n currentChannel: Channel;\r\n availableChannels: Channel[];\r\n resolveWith: (result?: any) => void;\r\n variantsPreview$: Observable<Array<{ id: string; name: string; price: number; pricePreview: number }>>;\r\n priceFactorControl = new FormControl(1);\r\n selectedChannelIdControl = new FormControl();\r\n\r\n // assigned by ModalService.fromComponent() call\r\n productIds: string[];\r\n productVariantIds: string[] | undefined;\r\n currentChannelIds: string[];\r\n\r\n get isProductVariantMode(): boolean {\r\n return this.productVariantIds != null;\r\n }\r\n\r\n constructor(private dataService: DataService, private notificationService: NotificationService) {}\r\n\r\n ngOnInit() {\r\n const activeChannelId$ = this.dataService.client\r\n .userStatus()\r\n .mapSingle(({ userStatus }) => userStatus.activeChannelId);\r\n const allChannels$ = this.dataService.settings.getChannels().mapSingle(data => data.channels);\r\n\r\n combineLatest(activeChannelId$, allChannels$).subscribe(([activeChannelId, channels]) => {\r\n // tslint:disable-next-line:no-non-null-assertion\r\n this.currentChannel = channels.find(c => c.id === activeChannelId)!;\r\n this.availableChannels = channels;\r\n });\r\n\r\n this.selectedChannelIdControl.valueChanges.subscribe(ids => {\r\n this.selectChannel(ids);\r\n });\r\n\r\n this.variantsPreview$ = combineLatest(\r\n from(this.getTopVariants(10)),\r\n this.priceFactorControl.valueChanges.pipe(startWith(1)),\r\n ).pipe(\r\n map(([variants, factor]) => {\r\n return variants.map(v => ({\r\n id: v.id,\r\n name: v.name,\r\n price: v.price,\r\n pricePreview: v.price * +factor,\r\n }));\r\n }),\r\n );\r\n }\r\n\r\n selectChannel(channelIds: string[]) {\r\n this.selectedChannel = this.availableChannels.find(c => c.id === channelIds[0]);\r\n }\r\n\r\n assign() {\r\n const selectedChannel = this.selectedChannel;\r\n if (selectedChannel) {\r\n if (!this.isProductVariantMode) {\r\n this.dataService.product\r\n .assignProductsToChannel({\r\n channelId: selectedChannel.id,\r\n productIds: this.productIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-product-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n });\r\n this.resolveWith(true);\r\n });\r\n } else if (this.productVariantIds) {\r\n this.dataService.product\r\n .assignVariantsToChannel({\r\n channelId: selectedChannel.id,\r\n productVariantIds: this.productVariantIds,\r\n priceFactor: +this.priceFactorControl.value,\r\n })\r\n .subscribe(() => {\r\n this.notificationService.success(_('catalog.assign-variant-to-channel-success'), {\r\n channel: selectedChannel.code,\r\n });\r\n this.resolveWith(true);\r\n });\r\n }\r\n }\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n private async getTopVariants(take: number): Promise<ProductVariantFragment[]> {\r\n const variants: ProductVariantFragment[] = [];\r\n\r\n for (let i = 0; i < this.productIds.length && variants.length < take; i++) {\r\n const productVariants = await this.dataService.product\r\n .getProduct(this.productIds[i], { take: this.isProductVariantMode ? undefined : take })\r\n .mapSingle(({ product }) => {\r\n const _variants = product ? product.variantList.items : [];\r\n return _variants.filter(v =>\r\n this.isProductVariantMode ? this.productVariantIds?.includes(v.id) : true,\r\n );\r\n })\r\n .toPromise();\r\n variants.push(...(productVariants || []));\r\n }\r\n return variants.slice(0, take);\r\n }\r\n}\r\n","/**\r\n * @description\r\n * Like String.prototype.replace(), but replaces the last instance\r\n * rather than the first.\r\n */\r\nexport function replaceLast(target: string | undefined | null, search: string, replace: string): string {\r\n if (!target) {\r\n return '';\r\n }\r\n const lastIndex = target.lastIndexOf(search);\r\n if (lastIndex === -1) {\r\n return target;\r\n }\r\n const head = target.substr(0, lastIndex);\r\n const tail = target.substr(lastIndex).replace(search, replace);\r\n return head + tail;\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport {\r\n CreateProductInput,\r\n CreateProductVariantInput,\r\n DataService,\r\n DeletionResult,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n GetProductWithVariantsQuery,\r\n LanguageCode,\r\n UpdateProductInput,\r\n UpdateProductMutation,\r\n UpdateProductOptionInput,\r\n UpdateProductVariantInput,\r\n UpdateProductVariantsMutation,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { forkJoin, Observable, of, throwError } from 'rxjs';\r\nimport { map, mergeMap, shareReplay, switchMap } from 'rxjs/operators';\r\n\r\nimport { CreateProductVariantsConfig } from '../../components/generate-product-variants/generate-product-variants.component';\r\n\r\nimport { replaceLast } from './replace-last';\r\n\r\n/**\r\n * Handles the logic for making the API calls to perform CRUD operations on a Product and its related\r\n * entities. This logic was extracted out of the component because it became too large and hard to follow.\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductDetailService {\r\n constructor(private dataService: DataService) {}\r\n\r\n getFacets(): Observable<FacetWithValuesFragment[]> {\r\n return this.dataService.facet.getAllFacets().mapSingle(data => data.facets.items);\r\n }\r\n\r\n getTaxCategories() {\r\n return this.dataService.settings\r\n .getTaxCategories()\r\n .mapSingle(data => data.taxCategories)\r\n .pipe(shareReplay(1));\r\n }\r\n\r\n createProductWithVariants(\r\n input: CreateProductInput,\r\n createVariantsConfig: CreateProductVariantsConfig,\r\n languageCode: LanguageCode,\r\n ) {\r\n const createProduct$ = this.dataService.product.createProduct(input);\r\n const nonEmptyOptionGroups = createVariantsConfig.groups.filter(g => 0 < g.values.length);\r\n const createOptionGroups$ = this.createProductOptionGroups(nonEmptyOptionGroups, languageCode);\r\n\r\n return forkJoin(createProduct$, createOptionGroups$).pipe(\r\n mergeMap(([{ createProduct }, optionGroups]) => {\r\n const addOptionsToProduct$ = optionGroups.length\r\n ? forkJoin(\r\n optionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: createProduct.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n )\r\n : of([]);\r\n return addOptionsToProduct$.pipe(\r\n map(() => {\r\n return { createProduct, optionGroups };\r\n }),\r\n );\r\n }),\r\n mergeMap(({ createProduct, optionGroups }) => {\r\n const variants = createVariantsConfig.variants.map(v => {\r\n const optionIds = optionGroups.length\r\n ? v.optionValues.map((optionName, index) => {\r\n const option = optionGroups[index].options.find(o => o.name === optionName);\r\n if (!option) {\r\n throw new Error(\r\n `Could not find a matching ProductOption \"${optionName}\" when creating variant`,\r\n );\r\n }\r\n return option.id;\r\n })\r\n : [];\r\n return {\r\n ...v,\r\n optionIds,\r\n };\r\n });\r\n const options = optionGroups.map(og => og.options).reduce((flat, o) => [...flat, ...o], []);\r\n return this.createProductVariants(createProduct, variants, options, languageCode);\r\n }),\r\n );\r\n }\r\n\r\n createProductOptionGroups(groups: Array<{ name: string; values: string[] }>, languageCode: LanguageCode) {\r\n return groups.length\r\n ? forkJoin(\r\n groups.map(c => {\r\n return this.dataService.product\r\n .createProductOptionGroups({\r\n code: normalizeString(c.name, '-'),\r\n translations: [{ languageCode, name: c.name }],\r\n options: c.values.map(v => ({\r\n code: normalizeString(v, '-'),\r\n translations: [{ languageCode, name: v }],\r\n })),\r\n })\r\n .pipe(map(data => data.createProductOptionGroup));\r\n }),\r\n )\r\n : of([]);\r\n }\r\n\r\n createProductVariants(\r\n product: { name: string; id: string },\r\n variantData: Array<{ price: number; sku: string; stock: number; optionIds: string[] }>,\r\n options: Array<{ id: string; name: string }>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants: CreateProductVariantInput[] = variantData.map(v => {\r\n const name = options.length\r\n ? `${product.name} ${v.optionIds\r\n .map(id => options.find(o => o.id === id))\r\n .filter(notNullOrUndefined)\r\n .map(o => o.name)\r\n .join(' ')}`\r\n : product.name;\r\n return {\r\n productId: product.id,\r\n price: v.price,\r\n sku: v.sku,\r\n stockOnHand: v.stock,\r\n translations: [\r\n {\r\n languageCode,\r\n name,\r\n },\r\n ],\r\n optionIds: v.optionIds,\r\n };\r\n });\r\n return this.dataService.product.createProductVariants(variants).pipe(\r\n map(({ createProductVariants }) => ({\r\n createProductVariants,\r\n productId: product.id,\r\n })),\r\n );\r\n }\r\n\r\n updateProduct(updateOptions: {\r\n product: NonNullable<GetProductWithVariantsQuery['product']>;\r\n languageCode: LanguageCode;\r\n autoUpdate: boolean;\r\n productInput?: UpdateProductInput;\r\n variantsInput?: UpdateProductVariantInput[];\r\n }) {\r\n const { product, languageCode, autoUpdate, productInput, variantsInput } = updateOptions;\r\n const updateOperations: Array<Observable<UpdateProductMutation | UpdateProductVariantsMutation>> = [];\r\n const updateVariantsInput = variantsInput || [];\r\n\r\n const variants$ = autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n if (productInput) {\r\n updateOperations.push(this.dataService.product.updateProduct(productInput));\r\n const productOldName = findTranslation(product, languageCode)?.name ?? '';\r\n const productNewName = findTranslation(productInput, languageCode)?.name;\r\n if (productNewName && productOldName !== productNewName && autoUpdate) {\r\n for (const variant of variants) {\r\n const currentVariantName = findTranslation(variant, languageCode)?.name || '';\r\n let variantInput: UpdateProductVariantInput;\r\n const existingVariantInput = updateVariantsInput.find(i => i.id === variant.id);\r\n if (existingVariantInput) {\r\n variantInput = existingVariantInput;\r\n } else {\r\n variantInput = {\r\n id: variant.id,\r\n translations: [{ languageCode, name: currentVariantName }],\r\n };\r\n updateVariantsInput.push(variantInput);\r\n }\r\n const variantTranslation = findTranslation(variantInput, languageCode);\r\n if (variantTranslation) {\r\n if (variantTranslation.name) {\r\n variantTranslation.name = replaceLast(\r\n variantTranslation.name,\r\n productOldName,\r\n productNewName,\r\n );\r\n } else {\r\n // The variant translation was falsy, which occurs\r\n // when defining the product name for a new translation\r\n // language that had not yet been defined.\r\n variantTranslation.name = [\r\n productNewName,\r\n ...variant.options.map(o => o.name),\r\n ].join(' ');\r\n }\r\n }\r\n }\r\n }\r\n }\r\n if (updateVariantsInput.length) {\r\n updateOperations.push(\r\n this.dataService.product.updateProductVariants(updateVariantsInput),\r\n );\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n );\r\n }\r\n\r\n updateProductOption(\r\n input: UpdateProductOptionInput & { autoUpdate: boolean },\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const variants$ = input.autoUpdate\r\n ? this.dataService.product\r\n .getProductVariants({}, product.id)\r\n .mapSingle(({ productVariants }) => productVariants.items)\r\n : of([]);\r\n\r\n return variants$.pipe(\r\n mergeMap(variants => {\r\n let updateProductVariantNames$: Observable<any> = of([]);\r\n if (input.autoUpdate) {\r\n // Update any ProductVariants' names which include the option name\r\n let oldOptionName: string | undefined;\r\n const newOptionName = findTranslation(input, languageCode)?.name;\r\n if (!newOptionName) {\r\n updateProductVariantNames$ = of([]);\r\n }\r\n const variantsToUpdate: UpdateProductVariantInput[] = [];\r\n for (const variant of variants) {\r\n if (variant.options.map(o => o.id).includes(input.id)) {\r\n if (!oldOptionName) {\r\n oldOptionName = findTranslation(\r\n variant.options.find(o => o.id === input.id),\r\n languageCode,\r\n )?.name;\r\n }\r\n const variantName = findTranslation(variant, languageCode)?.name || '';\r\n if (oldOptionName && newOptionName && variantName.includes(oldOptionName)) {\r\n variantsToUpdate.push({\r\n id: variant.id,\r\n translations: [\r\n {\r\n languageCode,\r\n name: replaceLast(variantName, oldOptionName, newOptionName),\r\n },\r\n ],\r\n });\r\n }\r\n }\r\n }\r\n if (variantsToUpdate.length) {\r\n updateProductVariantNames$ =\r\n this.dataService.product.updateProductVariants(variantsToUpdate);\r\n }\r\n }\r\n return this.dataService.product\r\n .updateProductOption(input)\r\n .pipe(mergeMap(() => updateProductVariantNames$));\r\n }),\r\n );\r\n }\r\n\r\n deleteProductVariant(id: string, productId: string) {\r\n return this.dataService.product.deleteProductVariant(id).pipe(\r\n switchMap(result => {\r\n if (result.deleteProductVariant.result === DeletionResult.DELETED) {\r\n return this.dataService.product.getProduct(productId).single$;\r\n } else {\r\n return throwError(result.deleteProductVariant.message);\r\n }\r\n }),\r\n );\r\n }\r\n}\r\n","import { operate } from '../util/lift';\nimport { createOperatorSubscriber } from './OperatorSubscriber';\nimport { innerFrom } from '../observable/innerFrom';\nimport { noop } from '../util/noop';\nexport function skipUntil(notifier) {\n return operate((source, subscriber) => {\n let taking = false;\n const skipSubscriber = createOperatorSubscriber(subscriber, () => {\n skipSubscriber === null || skipSubscriber === void 0 ? void 0 : skipSubscriber.unsubscribe();\n taking = true;\n }, noop);\n innerFrom(notifier).subscribe(skipSubscriber);\n source.subscribe(createOperatorSubscriber(subscriber, (value) => taking && subscriber.next(value)));\n });\n}\n","<div class=\"input-wrapper\" [class.focus]=\"isFocussed\" (click)=\"textArea.focus()\">\r\n <div class=\"chips\" *ngIf=\"0 < options.length\">\r\n <vdr-chip\r\n *ngFor=\"let option of options; last as isLast\"\r\n [icon]=\"option.locked ? 'lock' : 'times'\"\r\n [class.selected]=\"isLast && lastSelected\"\r\n [class.locked]=\"option.locked\"\r\n [colorFrom]=\"groupName\"\r\n (iconClick)=\"removeOption(option)\"\r\n >\r\n {{ option.name }}\r\n </vdr-chip>\r\n </div>\r\n <textarea\r\n #textArea\r\n (keyup)=\"handleKey($event)\"\r\n (focus)=\"isFocussed = true\"\r\n (blur)=\"handleBlur()\"\r\n [(ngModel)]=\"input\"\r\n [disabled]=\"disabled\"\r\n ></textarea>\r\n</div>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n ElementRef,\r\n forwardRef,\r\n Input,\r\n Provider,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport const OPTION_VALUE_INPUT_VALUE_ACCESSOR: Provider = {\r\n provide: NG_VALUE_ACCESSOR,\r\n useExisting: forwardRef(() => OptionValueInputComponent),\r\n multi: true,\r\n};\r\n\r\n@Component({\r\n selector: 'vdr-option-value-input',\r\n templateUrl: './option-value-input.component.html',\r\n styleUrls: ['./option-value-input.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n providers: [OPTION_VALUE_INPUT_VALUE_ACCESSOR],\r\n})\r\nexport class OptionValueInputComponent implements ControlValueAccessor {\r\n @Input() groupName = '';\r\n @ViewChild('textArea', { static: true }) textArea: ElementRef<HTMLTextAreaElement>;\r\n options: Array<{ name: string; locked: boolean }>;\r\n disabled = false;\r\n input = '';\r\n isFocussed = false;\r\n lastSelected = false;\r\n onChangeFn: (value: any) => void;\r\n onTouchFn: (value: any) => void;\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n registerOnChange(fn: any): void {\r\n this.onChangeFn = fn;\r\n }\r\n\r\n registerOnTouched(fn: any): void {\r\n this.onTouchFn = fn;\r\n }\r\n\r\n setDisabledState(isDisabled: boolean): void {\r\n this.disabled = isDisabled;\r\n this.changeDetector.markForCheck();\r\n }\r\n\r\n writeValue(obj: any): void {\r\n this.options = obj || [];\r\n }\r\n\r\n focus() {\r\n this.textArea.nativeElement.focus();\r\n }\r\n\r\n removeOption(option: { name: string; locked: boolean }) {\r\n if (!option.locked) {\r\n this.options = this.options.filter(o => o.name !== option.name);\r\n this.onChangeFn(this.options);\r\n }\r\n }\r\n\r\n handleKey(event: KeyboardEvent) {\r\n switch (event.key) {\r\n case ',':\r\n case 'Enter':\r\n this.addOptionValue();\r\n event.preventDefault();\r\n break;\r\n case 'Backspace':\r\n if (this.lastSelected) {\r\n this.removeLastOption();\r\n this.lastSelected = false;\r\n } else if (this.input === '') {\r\n this.lastSelected = true;\r\n }\r\n break;\r\n default:\r\n this.lastSelected = false;\r\n }\r\n }\r\n\r\n handleBlur() {\r\n this.isFocussed = false;\r\n this.addOptionValue();\r\n }\r\n\r\n private addOptionValue() {\r\n this.options = unique([...this.options, ...this.parseInputIntoOptions(this.input)]);\r\n this.input = '';\r\n this.onChangeFn(this.options);\r\n }\r\n\r\n private parseInputIntoOptions(input: string): Array<{ name: string; locked: boolean }> {\r\n return input\r\n .split(/[,\\n]/)\r\n .map(s => s.trim())\r\n .filter(s => s !== '')\r\n .map(s => ({ name: s, locked: false }));\r\n }\r\n\r\n private removeLastOption() {\r\n if (!this.options[this.options.length - 1].locked) {\r\n this.options = this.options.slice(0, this.options.length - 1);\r\n }\r\n }\r\n}\r\n","<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input\r\n placeholder=\"e.g. Size\"\r\n clrInput\r\n [(ngModel)]=\"group.name\"\r\n name=\"name\"\r\n required\r\n (keydown.enter)=\"handleEnter($event, optionValueInputComponent)\"\r\n />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n <div class=\"remove-group\">\r\n <button\r\n class=\"btn btn-icon btn-warning-outline\"\r\n [title]=\"'catalog.remove-option' | translate\"\r\n (click)=\"removeOption(group.name)\"\r\n >\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button class=\"btn btn-primary-outline btn-sm\" (click)=\"addOption()\">\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th *ngIf=\"1 < variants.length\">{{ 'common.create' | translate }}</th>\r\n <th *ngIf=\"1 < variants.length\">{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tr\r\n *ngFor=\"let variant of variants; trackBy: trackByFn\"\r\n [class.disabled]=\"!variantFormValues[variant.id].enabled\"\r\n >\r\n <td *ngIf=\"1 < variants.length\">\r\n <input\r\n type=\"checkbox\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].enabled\"\r\n clrCheckbox\r\n />\r\n </td>\r\n <td *ngIf=\"1 < variants.length\">\r\n {{ variant.values.join(' ') }}\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"text\"\r\n (change)=\"onFormChange()\"\r\n [(ngModel)]=\"variantFormValues[variant.id].sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variantFormValues[variant.id].price\"\r\n (ngModelChange)=\"onFormChange()\"\r\n [currencyCode]=\"currencyCode\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n </td>\r\n <td>\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variantFormValues[variant.id].stock\"\r\n (change)=\"onFormChange()\"\r\n min=\"0\"\r\n step=\"1\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { Component, EventEmitter, OnInit, Output } from '@angular/core';\r\nimport { generateAllCombinations } from '@vendure/common/lib/shared-utils';\r\n\r\nimport { CurrencyCode } from '@vendure/admin-ui/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\nimport { OptionValueInputComponent } from '../option-value-input/option-value-input.component';\r\n\r\nconst DEFAULT_VARIANT_CODE = '__DEFAULT_VARIANT__';\r\nexport type CreateVariantValues = {\r\n optionValues: string[];\r\n enabled: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n};\r\nexport type CreateProductVariantsConfig = {\r\n groups: Array<{ name: string; values: string[] }>;\r\n variants: CreateVariantValues[];\r\n};\r\n\r\n@Component({\r\n selector: 'vdr-generate-product-variants',\r\n templateUrl: './generate-product-variants.component.html',\r\n styleUrls: ['./generate-product-variants.component.scss'],\r\n})\r\nexport class GenerateProductVariantsComponent implements OnInit {\r\n @Output() variantsChange = new EventEmitter<CreateProductVariantsConfig>();\r\n optionGroups: Array<{ name: string; values: Array<{ name: string; locked: boolean }> }> = [];\r\n currencyCode: CurrencyCode;\r\n variants: Array<{ id: string; values: string[] }>;\r\n variantFormValues: { [id: string]: CreateVariantValues } = {};\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n\r\n this.generateVariants();\r\n }\r\n\r\n addOption() {\r\n this.optionGroups.push({ name: '', values: [] });\r\n }\r\n\r\n removeOption(name: string) {\r\n this.optionGroups = this.optionGroups.filter(g => g.name !== name);\r\n this.generateVariants();\r\n }\r\n\r\n generateVariants() {\r\n const totalValuesCount = this.optionGroups.reduce((sum, group) => sum + group.values.length, 0);\r\n const groups = totalValuesCount\r\n ? this.optionGroups.map(g => g.values.map(v => v.name))\r\n : [[DEFAULT_VARIANT_CODE]];\r\n this.variants = generateAllCombinations(groups).map(values => ({ id: values.join('|'), values }));\r\n\r\n this.variants.forEach(variant => {\r\n if (!this.variantFormValues[variant.id]) {\r\n this.variantFormValues[variant.id] = {\r\n optionValues: variant.values,\r\n enabled: true,\r\n price: this.copyFromDefault(variant.id, 'price', 0),\r\n sku: this.copyFromDefault(variant.id, 'sku', ''),\r\n stock: this.copyFromDefault(variant.id, 'stock', 0),\r\n };\r\n }\r\n });\r\n this.onFormChange();\r\n }\r\n\r\n trackByFn(index: number, variant: { name: string; values: string[] }) {\r\n return variant.values.join('|');\r\n }\r\n\r\n handleEnter(event: KeyboardEvent, optionValueInputComponent: OptionValueInputComponent) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n optionValueInputComponent.focus();\r\n }\r\n\r\n onFormChange() {\r\n const variantsToCreate = this.variants.map(v => this.variantFormValues[v.id]).filter(v => v.enabled);\r\n this.variantsChange.emit({\r\n groups: this.optionGroups.map(og => ({ name: og.name, values: og.values.map(v => v.name) })),\r\n variants: variantsToCreate,\r\n });\r\n }\r\n\r\n private copyFromDefault<T extends keyof CreateVariantValues>(\r\n variantId: string,\r\n prop: T,\r\n value: CreateVariantValues[T],\r\n ): CreateVariantValues[T] {\r\n return variantId !== DEFAULT_VARIANT_CODE\r\n ? this.variantFormValues[DEFAULT_VARIANT_CODE][prop]\r\n : value;\r\n }\r\n}\r\n","<table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <ng-container *ngFor=\"let optionGroup of optionGroups | sort: 'id'\">\r\n <th>{{ optionGroup.name }}</th>\r\n </ng-container>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th>{{ 'common.enabled' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr *ngFor=\"let variant of variants | paginate: paginationConfig; index as i; trackBy: trackByFn\">\r\n <ng-container *ngIf=\"formGroupMap.get(variant.id) as formGroup\" [formGroup]=\"formGroup\">\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"getFeaturedAsset(variant) as featuredAsset; else placeholder\"\r\n [src]=\"featuredAsset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #placeholder>\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 </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\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 </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\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 </td>\r\n <ng-container *ngFor=\"let option of variant.options | sort: 'groupId'\">\r\n <td\r\n class=\"left align-middle\"\r\n [class.disabled]=\"!formGroup.get('enabled')!.value\"\r\n [style.color]=\"optionGroupName(option.groupId) | stringToColor\"\r\n >\r\n {{ option.name }}\r\n </td>\r\n </ng-container>\r\n <td class=\"left align-middle price\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\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 </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n min=\"0\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-input-container>\r\n </td>\r\n <td class=\"left align-middle stock\" [class.disabled]=\"!formGroup.get('enabled')!.value\">\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"enabled\"\r\n formControlName=\"enabled\"\r\n [vdrDisabled]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </clr-toggle-wrapper>\r\n </td>\r\n </ng-container>\r\n </tr>\r\n </tbody>\r\n</table>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n Input,\r\n OnDestroy,\r\n OnInit,\r\n} from '@angular/core';\r\nimport { FormArray, FormGroup } from '@angular/forms';\r\nimport { Permission, ProductDetailFragment, ProductVariantFragment } from '@vendure/admin-ui/core';\r\nimport { Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\r\n\r\nimport { PaginationConfig, SelectedAssets } from '../product-detail/product-detail.types';\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-table',\r\n templateUrl: './product-variants-table.component.html',\r\n styleUrls: ['./product-variants-table.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductVariantsTableComponent implements OnInit, OnDestroy {\r\n @Input('productVariantsFormArray') formArray: FormArray;\r\n @Input() variants: ProductVariantFragment[];\r\n @Input() paginationConfig: PaginationConfig;\r\n @Input() channelPriceIncludesTax: boolean;\r\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\r\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\r\n formGroupMap = new Map<string, FormGroup>();\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n private subscription: Subscription;\r\n\r\n constructor(private changeDetector: ChangeDetectorRef) {}\r\n\r\n ngOnInit() {\r\n this.subscription = this.formArray.valueChanges\r\n .pipe(\r\n map(value => value.length),\r\n debounceTime(1),\r\n distinctUntilChanged(),\r\n )\r\n .subscribe(() => {\r\n this.buildFormGroupMap();\r\n });\r\n\r\n this.buildFormGroupMap();\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.subscription) {\r\n this.subscription.unsubscribe();\r\n }\r\n }\r\n\r\n trackByFn(index: number, item: any) {\r\n if ((item as any).id != null) {\r\n return (item as any).id;\r\n } else {\r\n return index;\r\n }\r\n }\r\n\r\n getFeaturedAsset(variant: ProductVariantFragment) {\r\n return this.pendingAssetChanges[variant.id]?.featuredAsset || variant.featuredAsset;\r\n }\r\n\r\n optionGroupName(optionGroupId: string): string | undefined {\r\n const group = this.optionGroups.find(g => g.id === optionGroupId);\r\n return group && group.name;\r\n }\r\n\r\n private buildFormGroupMap() {\r\n this.formGroupMap.clear();\r\n for (const controlGroup of this.formArray.controls) {\r\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>{{ 'catalog.update-product-option' | translate }}</ng-template>\r\n<vdr-form-field [label]=\"'catalog.option-name' | translate\" for=\"name\">\r\n <input\r\n id=\"name\"\r\n type=\"text\"\r\n #nameInput=\"ngModel\"\r\n [(ngModel)]=\"name\"\r\n required\r\n (input)=\"updateCode($event.target.value)\"\r\n />\r\n</vdr-form-field>\r\n<vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input id=\"code\" type=\"text\" #codeInput=\"ngModel\" required [(ngModel)]=\"code\" pattern=\"[a-z0-9_-]+\" />\r\n</vdr-form-field>\r\n<clr-checkbox-wrapper>\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"updateVariantName\" />\r\n <label>{{ 'catalog.auto-update-option-variant-name' | translate }}</label>\r\n</clr-checkbox-wrapper>\r\n<section *ngIf=\"customFields.length\">\r\n <label>{{ 'common.custom-fields' | translate }}</label>\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductOption\"\r\n [customFields]=\"customFields\"\r\n [customFieldsFormGroup]=\"customFieldsForm\"\r\n [readonly]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n</section>\r\n\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button\r\n type=\"submit\"\r\n (click)=\"update()\"\r\n [disabled]=\"\r\n nameInput.invalid ||\r\n codeInput.invalid ||\r\n (nameInput.pristine && codeInput.pristine && customFieldsForm.pristine)\r\n \"\r\n class=\"btn btn-primary\"\r\n >\r\n {{ 'catalog.update-product-option' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { FormControl, FormGroup } from '@angular/forms';\r\nimport {\r\n CustomFieldConfig,\r\n LanguageCode,\r\n ProductVariantFragment,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { createUpdatedTranslatable } from '@vendure/admin-ui/core';\r\nimport { Dialog } from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\n\r\n@Component({\r\n selector: 'vdr-update-product-option-dialog',\r\n templateUrl: './update-product-option-dialog.component.html',\r\n styleUrls: ['./update-product-option-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class UpdateProductOptionDialogComponent\r\n implements Dialog<UpdateProductOptionInput & { autoUpdate: boolean }>, OnInit\r\n{\r\n resolveWith: (result?: UpdateProductOptionInput & { autoUpdate: boolean }) => void;\r\n updateVariantName = true;\r\n // Provided by caller\r\n productOption: ProductVariantFragment['options'][number];\r\n activeLanguage: LanguageCode;\r\n name: string;\r\n code: string;\r\n customFields: CustomFieldConfig[];\r\n codeInputTouched = false;\r\n customFieldsForm: FormGroup;\r\n\r\n ngOnInit(): void {\r\n const currentTranslation = this.productOption.translations.find(\r\n t => t.languageCode === this.activeLanguage,\r\n );\r\n this.name = currentTranslation?.name ?? '';\r\n this.code = this.productOption.code;\r\n this.customFieldsForm = new FormGroup({});\r\n if (this.customFields) {\r\n const cfCurrentTranslation =\r\n (currentTranslation && (currentTranslation as any).customFields) || {};\r\n\r\n for (const fieldDef of this.customFields) {\r\n const key = fieldDef.name;\r\n const value =\r\n fieldDef.type === 'localeString'\r\n ? cfCurrentTranslation[key]\r\n : (this.productOption as any).customFields[key];\r\n this.customFieldsForm.addControl(fieldDef.name, new FormControl(value));\r\n }\r\n }\r\n }\r\n\r\n update() {\r\n const result = createUpdatedTranslatable({\r\n translatable: this.productOption,\r\n languageCode: this.activeLanguage,\r\n updatedFields: {\r\n code: this.code,\r\n name: this.name,\r\n customFields: this.customFieldsForm.value,\r\n },\r\n customFieldConfig: this.customFields,\r\n defaultTranslation: {\r\n languageCode: this.activeLanguage,\r\n name: '',\r\n },\r\n });\r\n this.resolveWith({ ...result, autoUpdate: this.updateVariantName });\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n\r\n updateCode(nameValue: string) {\r\n if (!this.codeInputTouched && !this.productOption.code) {\r\n this.code = normalizeString(nameValue, '-');\r\n }\r\n }\r\n}\r\n","<label class=\"clr-control-label\">{{ 'catalog.taxes' | translate }}</label>\r\n<div *ngIf=\"priceIncludesTax\" class=\"value\">\r\n {{ 'catalog.price-includes-tax-at' | translate: { rate: taxRate$ | async } }}\r\n</div>\r\n<div *ngIf=\"!priceIncludesTax\" class=\"value\">\r\n {{\r\n 'catalog.price-with-tax-in-default-zone'\r\n | translate: { price: grossPrice$ | async | localeCurrency: currencyCode, rate: taxRate$ | async }\r\n }}\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs';\r\nimport { map } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-variant-price-detail',\r\n templateUrl: './variant-price-detail.component.html',\r\n styleUrls: ['./variant-price-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class VariantPriceDetailComponent implements OnInit, OnChanges {\r\n @Input() priceIncludesTax: boolean;\r\n @Input() price: number;\r\n @Input() currencyCode: string;\r\n @Input() taxCategoryId: string;\r\n\r\n grossPrice$: Observable<number>;\r\n taxRate$: Observable<number>;\r\n\r\n private priceChange$ = new BehaviorSubject<number>(0);\r\n private taxCategoryIdChange$ = new BehaviorSubject<string>('');\r\n\r\n constructor(private dataService: DataService) {}\r\n\r\n ngOnInit() {\r\n const taxRates$ = this.dataService.settings\r\n .getTaxRatesSimple(999, 0, 'cache-first')\r\n .mapStream(data => data.taxRates.items);\r\n const activeChannel$ = this.dataService.settings\r\n .getActiveChannel('cache-first')\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.activeChannel);\r\n\r\n this.taxRate$ = combineLatest(activeChannel$, taxRates$, this.taxCategoryIdChange$).pipe(\r\n map(([channel, taxRates, taxCategoryId]) => {\r\n const defaultTaxZone = channel.defaultTaxZone;\r\n if (!defaultTaxZone) {\r\n return 0;\r\n }\r\n const applicableRate = taxRates.find(\r\n taxRate => taxRate.zone.id === defaultTaxZone.id && taxRate.category.id === taxCategoryId,\r\n );\r\n\r\n if (!applicableRate) {\r\n return 0;\r\n }\r\n return applicableRate.value;\r\n }),\r\n );\r\n\r\n this.grossPrice$ = combineLatest(this.taxRate$, this.priceChange$).pipe(\r\n map(([taxRate, price]) => {\r\n return Math.round(price * ((100 + taxRate) / 100));\r\n }),\r\n );\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if ('price' in changes) {\r\n this.priceChange$.next(changes.price.currentValue);\r\n }\r\n if ('taxCategoryId' in changes) {\r\n this.taxCategoryIdChange$.next(changes.taxCategoryId.currentValue);\r\n }\r\n }\r\n}\r\n","<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=\"0\"\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","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n Input,\r\n OnChanges,\r\n OnDestroy,\r\n OnInit,\r\n Output,\r\n SimpleChanges,\r\n} from '@angular/core';\r\nimport { FormArray, FormGroup } from '@angular/forms';\r\nimport {\r\n CustomFieldConfig,\r\n DataService,\r\n FacetValueFragment,\r\n FacetWithValuesFragment,\r\n flattenFacetValues,\r\n GlobalFlag,\r\n LanguageCode,\r\n ModalService,\r\n Permission,\r\n ProductDetailFragment,\r\n ProductOptionFragment,\r\n ProductVariantFragment,\r\n TaxCategory,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { Subscription } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';\r\n\r\nimport { AssetChange } from '../assets/assets.component';\r\nimport { PaginationConfig, SelectedAssets, VariantFormValue } from '../product-detail/product-detail.types';\r\nimport { UpdateProductOptionDialogComponent } from '../update-product-option-dialog/update-product-option-dialog.component';\r\n\r\nexport interface VariantAssetChange extends AssetChange {\r\n variantId: string;\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-list',\r\n templateUrl: './product-variants-list.component.html',\r\n styleUrls: ['./product-variants-list.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductVariantsListComponent implements OnChanges, OnInit, OnDestroy {\r\n @Input('productVariantsFormArray') formArray: FormArray;\r\n @Input() variants: ProductVariantFragment[];\r\n @Input() paginationConfig: PaginationConfig;\r\n @Input() channelPriceIncludesTax: boolean;\r\n @Input() taxCategories: TaxCategory[];\r\n @Input() facets: FacetWithValuesFragment[];\r\n @Input() optionGroups: ProductDetailFragment['optionGroups'];\r\n @Input() customFields: CustomFieldConfig[];\r\n @Input() customOptionFields: CustomFieldConfig[];\r\n @Input() activeLanguage: LanguageCode;\r\n @Input() pendingAssetChanges: { [variantId: string]: SelectedAssets };\r\n @Output() assignToChannel = new EventEmitter<ProductVariantFragment>();\r\n @Output() removeFromChannel = new EventEmitter<{\r\n channelId: string;\r\n variant: ProductVariantFragment;\r\n }>();\r\n @Output() assetChange = new EventEmitter<VariantAssetChange>();\r\n @Output() selectionChange = new EventEmitter<string[]>();\r\n @Output() selectFacetValueClick = new EventEmitter<string[]>();\r\n @Output() updateProductOption = new EventEmitter<UpdateProductOptionInput & { autoUpdate: boolean }>();\r\n selectedVariantIds: string[] = [];\r\n formGroupMap = new Map<string, FormGroup>();\r\n GlobalFlag = GlobalFlag;\r\n globalTrackInventory: boolean;\r\n globalOutOfStockThreshold: number;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n private facetValues: FacetValueFragment[];\r\n private subscription: Subscription;\r\n\r\n constructor(\r\n private changeDetector: ChangeDetectorRef,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.dataService.settings.getGlobalSettings('cache-first').single$.subscribe(({ globalSettings }) => {\r\n this.globalTrackInventory = globalSettings.trackInventory;\r\n this.globalOutOfStockThreshold = globalSettings.outOfStockThreshold;\r\n this.changeDetector.markForCheck();\r\n });\r\n this.subscription = this.formArray.valueChanges.subscribe(() => this.changeDetector.markForCheck());\r\n\r\n this.subscription.add(\r\n this.formArray.valueChanges\r\n .pipe(\r\n map(value => value.length),\r\n debounceTime(1),\r\n distinctUntilChanged(),\r\n )\r\n .subscribe(() => {\r\n this.buildFormGroupMap();\r\n }),\r\n );\r\n\r\n this.buildFormGroupMap();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges) {\r\n if ('facets' in changes && !!changes['facets'].currentValue) {\r\n this.facetValues = flattenFacetValues(this.facets);\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n if (this.subscription) {\r\n this.subscription.unsubscribe();\r\n }\r\n }\r\n\r\n isDefaultChannel(channelCode: string): boolean {\r\n return channelCode === DEFAULT_CHANNEL_CODE;\r\n }\r\n\r\n trackById(index: number, item: ProductVariantFragment) {\r\n return item.id;\r\n }\r\n\r\n inventoryIsNotTracked(formGroup: FormGroup): boolean {\r\n const trackInventory = formGroup.get('trackInventory')?.value;\r\n return (\r\n trackInventory === GlobalFlag.FALSE ||\r\n (trackInventory === GlobalFlag.INHERIT && this.globalTrackInventory === false)\r\n );\r\n }\r\n\r\n getTaxCategoryName(group: FormGroup): string {\r\n const control = group.get(['taxCategoryId']);\r\n if (control && this.taxCategories) {\r\n const match = this.taxCategories.find(t => t.id === control.value);\r\n return match ? match.name : '';\r\n }\r\n return '';\r\n }\r\n\r\n getSaleableStockLevel(variant: ProductVariantFragment) {\r\n const effectiveOutOfStockThreshold = variant.useGlobalOutOfStockThreshold\r\n ? this.globalOutOfStockThreshold\r\n : variant.outOfStockThreshold;\r\n return variant.stockOnHand - variant.stockAllocated - effectiveOutOfStockThreshold;\r\n }\r\n\r\n areAllSelected(): boolean {\r\n return !!this.variants && this.selectedVariantIds.length === this.variants.length;\r\n }\r\n\r\n onAssetChange(variantId: string, event: AssetChange) {\r\n this.assetChange.emit({\r\n variantId,\r\n ...event,\r\n });\r\n const index = this.variants.findIndex(v => v.id === variantId);\r\n this.formArray.at(index).markAsDirty();\r\n }\r\n\r\n toggleSelectAll() {\r\n if (this.areAllSelected()) {\r\n this.selectedVariantIds = [];\r\n } else {\r\n this.selectedVariantIds = this.variants.map(v => v.id);\r\n }\r\n this.selectionChange.emit(this.selectedVariantIds);\r\n }\r\n\r\n toggleSelectVariant(variantId: string) {\r\n const index = this.selectedVariantIds.indexOf(variantId);\r\n if (-1 < index) {\r\n this.selectedVariantIds.splice(index, 1);\r\n } else {\r\n this.selectedVariantIds.push(variantId);\r\n }\r\n this.selectionChange.emit(this.selectedVariantIds);\r\n }\r\n\r\n optionGroupName(optionGroupId: string): string | undefined {\r\n const group = this.optionGroups.find(g => g.id === optionGroupId);\r\n if (group) {\r\n const translation =\r\n group?.translations.find(t => t.languageCode === this.activeLanguage) ??\r\n group.translations[0];\r\n return translation.name;\r\n }\r\n }\r\n\r\n optionName(option: ProductOptionFragment) {\r\n const translation =\r\n option.translations.find(t => t.languageCode === this.activeLanguage) ?? option.translations[0];\r\n return translation.name;\r\n }\r\n\r\n pendingFacetValues(variant: ProductVariantFragment) {\r\n if (this.facets) {\r\n const formFacetValueIds = this.getFacetValueIds(variant.id);\r\n const variantFacetValueIds = variant.facetValues.map(fv => fv.id);\r\n return formFacetValueIds\r\n .filter(x => !variantFacetValueIds.includes(x))\r\n .map(id => this.facetValues.find(fv => fv.id === id))\r\n .filter(notNullOrUndefined);\r\n } else {\r\n return [];\r\n }\r\n }\r\n\r\n existingFacetValues(variant: ProductVariantFragment) {\r\n const formFacetValueIds = this.getFacetValueIds(variant.id);\r\n const intersection = [...formFacetValueIds].filter(x =>\r\n variant.facetValues.map(fv => fv.id).includes(x),\r\n );\r\n return intersection\r\n .map(id => variant.facetValues.find(fv => fv.id === id))\r\n .filter(notNullOrUndefined);\r\n }\r\n\r\n removeFacetValue(variant: ProductVariantFragment, facetValueId: string) {\r\n const formGroup = this.formGroupMap.get(variant.id);\r\n if (formGroup) {\r\n const newValue = (formGroup.value as VariantFormValue).facetValueIds.filter(\r\n id => id !== facetValueId,\r\n );\r\n formGroup.patchValue({\r\n facetValueIds: newValue,\r\n });\r\n formGroup.markAsDirty();\r\n }\r\n }\r\n\r\n isVariantSelected(variantId: string): boolean {\r\n return -1 < this.selectedVariantIds.indexOf(variantId);\r\n }\r\n\r\n editOption(option: ProductVariantFragment['options'][number]) {\r\n this.modalService\r\n .fromComponent(UpdateProductOptionDialogComponent, {\r\n size: 'md',\r\n locals: {\r\n productOption: option,\r\n activeLanguage: this.activeLanguage,\r\n customFields: this.customOptionFields,\r\n },\r\n })\r\n .subscribe(result => {\r\n if (result) {\r\n this.updateProductOption.emit(result);\r\n }\r\n });\r\n }\r\n\r\n private buildFormGroupMap() {\r\n this.formGroupMap.clear();\r\n for (const controlGroup of this.formArray.controls) {\r\n this.formGroupMap.set(controlGroup.value.id, controlGroup as FormGroup);\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n\r\n private getFacetValueIds(id: string): string[] {\r\n const formValue: VariantFormValue = this.formGroupMap.get(id)?.value;\r\n return formValue.facetValueIds;\r\n }\r\n}\r\n","<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","import { Location } from '@angular/common';\r\nimport { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n CreateProductInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n FacetWithValuesFragment,\r\n findTranslation,\r\n flattenFacetValues,\r\n GetProductWithVariantsQuery,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ProductDetailFragment,\r\n ProductVariantFragment,\r\n ServerConfigService,\r\n TaxCategoryFragment,\r\n unicodePatternValidator,\r\n UpdateProductInput,\r\n UpdateProductMutation,\r\n UpdateProductOptionInput,\r\n UpdateProductVariantInput,\r\n UpdateProductVariantsMutation,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { BehaviorSubject, combineLatest, EMPTY, merge, Observable } from 'rxjs';\r\nimport {\r\n debounceTime,\r\n distinctUntilChanged,\r\n map,\r\n mergeMap,\r\n shareReplay,\r\n skip,\r\n skipUntil,\r\n startWith,\r\n switchMap,\r\n take,\r\n takeUntil,\r\n tap,\r\n withLatestFrom,\r\n} from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ApplyFacetDialogComponent } from '../apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { CreateProductVariantsConfig } from '../generate-product-variants/generate-product-variants.component';\r\nimport { VariantAssetChange } from '../product-variants-list/product-variants-list.component';\r\n\r\nimport { PaginationConfig, SelectedAssets, TabName, VariantFormValue } from './product-detail.types';\r\n\r\n@Component({\r\n selector: 'vdr-product-detail',\r\n templateUrl: './product-detail.component.html',\r\n styleUrls: ['./product-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetProductWithVariantsQuery['product']>>\r\n implements OnInit, OnDestroy\r\n{\r\n activeTab$: Observable<TabName>;\r\n product$: Observable<NonNullable<GetProductWithVariantsQuery['product']>>;\r\n variants$: Observable<ProductVariantFragment[]>;\r\n taxCategories$: Observable<TaxCategoryFragment[]>;\r\n customFields: CustomFieldConfig[];\r\n customVariantFields: CustomFieldConfig[];\r\n customOptionGroupFields: CustomFieldConfig[];\r\n customOptionFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n filterInput = new FormControl('');\r\n assetChanges: SelectedAssets = {};\r\n variantAssetChanges: { [variantId: string]: SelectedAssets } = {};\r\n variantFacetValueChanges: { [variantId: string]: string[] } = {};\r\n productChannels$: Observable<ProductDetailFragment['channels']>;\r\n facetValues$: Observable<ProductDetailFragment['facetValues']>;\r\n facets$: Observable<FacetWithValuesFragment[]>;\r\n totalItems$: Observable<number>;\r\n currentPage$ = new BehaviorSubject(1);\r\n itemsPerPage$ = new BehaviorSubject(10);\r\n paginationConfig$: Observable<PaginationConfig>;\r\n selectedVariantIds: string[] = [];\r\n variantDisplayMode: 'card' | 'table' = 'card';\r\n createVariantsConfig: CreateProductVariantsConfig = { groups: [], variants: [] };\r\n channelPriceIncludesTax$: Observable<boolean>;\r\n // Used to store all ProductVariants which have been loaded.\r\n // It is needed when saving changes to variants.\r\n private productVariantMap = new Map<string, ProductVariantFragment>();\r\n public readonly updatePermissions = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n route: ActivatedRoute,\r\n router: Router,\r\n serverConfigService: ServerConfigService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private location: Location,\r\n private changeDetector: ChangeDetectorRef,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Product');\r\n this.customVariantFields = this.getCustomFieldConfig('ProductVariant');\r\n this.customOptionGroupFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.customOptionFields = this.getCustomFieldConfig('ProductOption');\r\n this.detailForm = this.formBuilder.group({\r\n product: this.formBuilder.group({\r\n enabled: true,\r\n name: ['', Validators.required],\r\n autoUpdateVariantNames: true,\r\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\r\n description: '',\r\n facetValueIds: [[]],\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n }),\r\n variants: this.formBuilder.array([]),\r\n });\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n this.product$ = this.entity$;\r\n this.totalItems$ = this.product$.pipe(map(product => product.variantList.totalItems));\r\n this.paginationConfig$ = combineLatest(this.totalItems$, this.itemsPerPage$, this.currentPage$).pipe(\r\n map(([totalItems, itemsPerPage, currentPage]) => ({\r\n totalItems,\r\n itemsPerPage,\r\n currentPage,\r\n })),\r\n );\r\n const variants$ = this.product$.pipe(map(product => product.variantList.items));\r\n const filterTerm$ = this.filterInput.valueChanges.pipe(\r\n startWith(''),\r\n debounceTime(200),\r\n shareReplay(),\r\n );\r\n const initialVariants$ = this.product$.pipe(map(p => p.variantList.items));\r\n const updatedVariants$ = combineLatest(filterTerm$, this.currentPage$, this.itemsPerPage$).pipe(\r\n skipUntil(initialVariants$),\r\n skip(1),\r\n switchMap(([term, currentPage, itemsPerPage]) => {\r\n return this.dataService.product\r\n .getProductVariants(\r\n {\r\n skip: (currentPage - 1) * itemsPerPage,\r\n take: itemsPerPage,\r\n ...(term\r\n ? { filter: { name: { contains: term }, sku: { contains: term } } }\r\n : {}),\r\n filterOperator: LogicalOperator.OR,\r\n },\r\n this.id,\r\n )\r\n .mapStream(({ productVariants }) => productVariants.items);\r\n }),\r\n shareReplay({ bufferSize: 1, refCount: true }),\r\n );\r\n this.variants$ = merge(initialVariants$, updatedVariants$).pipe(\r\n tap(variants => {\r\n for (const variant of variants) {\r\n this.productVariantMap.set(variant.id, variant);\r\n }\r\n }),\r\n );\r\n this.taxCategories$ = this.productDetailService.getTaxCategories().pipe(takeUntil(this.destroy$));\r\n this.activeTab$ = this.route.paramMap.pipe(map(qpm => qpm.get('tab') as any));\r\n\r\n combineLatest(updatedVariants$, this.languageCode$)\r\n .pipe(takeUntil(this.destroy$))\r\n .subscribe(([variants, languageCode]) => {\r\n this.buildVariantFormArray(variants, languageCode);\r\n });\r\n\r\n // FacetValues are provided initially by the nested array of the\r\n // Product entity, but once a fetch to get all Facets is made (as when\r\n // opening the FacetValue selector modal), then these additional values\r\n // are concatenated onto the initial array.\r\n this.facets$ = this.productDetailService.getFacets();\r\n const productFacetValues$ = this.product$.pipe(map(product => product.facetValues));\r\n const allFacetValues$ = this.facets$.pipe(map(flattenFacetValues));\r\n const productGroup = this.getProductFormGroup();\r\n\r\n const formFacetValueIdChanges$ = productGroup.valueChanges.pipe(\r\n map(val => val.facetValueIds as string[]),\r\n distinctUntilChanged(),\r\n );\r\n const formChangeFacetValues$ = combineLatest(\r\n formFacetValueIdChanges$,\r\n productFacetValues$,\r\n allFacetValues$,\r\n ).pipe(\r\n map(([ids, productFacetValues, allFacetValues]) => {\r\n const combined = [...productFacetValues, ...allFacetValues];\r\n return ids.map(id => combined.find(fv => fv.id === id)).filter(notNullOrUndefined);\r\n }),\r\n );\r\n\r\n this.facetValues$ = merge(productFacetValues$, formChangeFacetValues$);\r\n this.productChannels$ = this.product$.pipe(map(p => p.channels));\r\n this.channelPriceIncludesTax$ = this.dataService.settings\r\n .getActiveChannel('cache-first')\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.activeChannel.pricesIncludeTax)\r\n .pipe(shareReplay(1));\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n navigateToTab(tabName: TabName) {\r\n this.location.replaceState(\r\n this.router\r\n .createUrlTree(['./', { ...this.route.snapshot.params, tab: tabName }], {\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n })\r\n .toString(),\r\n );\r\n }\r\n\r\n isDefaultChannel(channelCode: string): boolean {\r\n return channelCode === DEFAULT_CHANNEL_CODE;\r\n }\r\n\r\n setPage(page: number) {\r\n this.currentPage$.next(page);\r\n }\r\n\r\n setItemsPerPage(value: string) {\r\n this.itemsPerPage$.next(+value);\r\n this.currentPage$.next(1);\r\n }\r\n\r\n assignToChannel() {\r\n this.productChannels$\r\n .pipe(\r\n take(1),\r\n switchMap(channels => {\r\n return this.modalService.fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: [this.id],\r\n currentChannelIds: channels.map(c => c.id),\r\n },\r\n });\r\n }),\r\n )\r\n .subscribe();\r\n }\r\n\r\n removeFromChannel(channelId: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.remove-product-from-channel'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('catalog.remove-from-channel'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? this.dataService.product.removeProductsFromChannel({\r\n channelId,\r\n productIds: [this.id],\r\n })\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('catalog.notify-remove-product-from-channel-success'));\r\n },\r\n err => {\r\n this.notificationService.error(_('catalog.notify-remove-product-from-channel-error'));\r\n },\r\n );\r\n }\r\n\r\n assignVariantToChannel(variant: ProductVariantFragment) {\r\n return this.modalService\r\n .fromComponent(AssignProductsToChannelDialogComponent, {\r\n size: 'lg',\r\n locals: {\r\n productIds: [this.id],\r\n productVariantIds: [variant.id],\r\n currentChannelIds: variant.channels.map(c => c.id),\r\n },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeVariantFromChannel({ channelId, variant }: { channelId: string; variant: ProductVariantFragment }) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.remove-product-variant-from-channel'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('catalog.remove-from-channel'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response\r\n ? this.dataService.product.removeVariantsFromChannel({\r\n channelId,\r\n productVariantIds: [variant.id],\r\n })\r\n : EMPTY,\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('catalog.notify-remove-variant-from-channel-success'));\r\n },\r\n err => {\r\n this.notificationService.error(_('catalog.notify-remove-variant-from-channel-error'));\r\n },\r\n );\r\n }\r\n\r\n assetsChanged(): boolean {\r\n return !!Object.values(this.assetChanges).length;\r\n }\r\n\r\n variantAssetsChanged(): boolean {\r\n return !!Object.keys(this.variantAssetChanges).length;\r\n }\r\n\r\n variantAssetChange(event: VariantAssetChange) {\r\n this.variantAssetChanges[event.variantId] = event;\r\n }\r\n\r\n /**\r\n * If creating a new product, automatically generate the slug based on the product name.\r\n */\r\n updateSlug(nameValue: string) {\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(take(1))\r\n .subscribe(([entity, languageCode]) => {\r\n const slugControl = this.detailForm.get(['product', 'slug']);\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n const currentSlugIsEmpty = !currentTranslation || !currentTranslation.slug;\r\n if (slugControl && slugControl.pristine && currentSlugIsEmpty) {\r\n slugControl.setValue(normalizeString(`${nameValue}`, '-'));\r\n }\r\n });\r\n }\r\n\r\n selectProductFacetValue() {\r\n this.displayFacetValueModal().subscribe(facetValueIds => {\r\n if (facetValueIds) {\r\n const productGroup = this.getProductFormGroup();\r\n const currentFacetValueIds = productGroup.value.facetValueIds;\r\n productGroup.patchValue({\r\n facetValueIds: unique([...currentFacetValueIds, ...facetValueIds]),\r\n });\r\n productGroup.markAsDirty();\r\n }\r\n });\r\n }\r\n\r\n updateProductOption(input: UpdateProductOptionInput & { autoUpdate: boolean }) {\r\n combineLatest(this.product$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode]) =>\r\n this.productDetailService.updateProductOption(input, product, languageCode),\r\n ),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOption',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOption',\r\n });\r\n },\r\n );\r\n }\r\n\r\n removeProductFacetValue(facetValueId: string) {\r\n const productGroup = this.getProductFormGroup();\r\n const currentFacetValueIds = productGroup.value.facetValueIds;\r\n productGroup.patchValue({\r\n facetValueIds: currentFacetValueIds.filter(id => id !== facetValueId),\r\n });\r\n productGroup.markAsDirty();\r\n }\r\n\r\n /**\r\n * Opens a dialog to select FacetValues to apply to the select ProductVariants.\r\n */\r\n selectVariantFacetValue(selectedVariantIds: string[]) {\r\n this.displayFacetValueModal()\r\n .pipe(withLatestFrom(this.variants$))\r\n .subscribe(([facetValueIds, variants]) => {\r\n if (facetValueIds) {\r\n for (const variantId of selectedVariantIds) {\r\n const index = variants.findIndex(v => v.id === variantId);\r\n const variant = variants[index];\r\n const existingFacetValueIds = variant ? variant.facetValues.map(fv => fv.id) : [];\r\n const variantFormGroup = (this.detailForm.get('variants') as FormArray).controls.find(\r\n c => c.value.id === variantId,\r\n );\r\n if (variantFormGroup) {\r\n const uniqueFacetValueIds = unique([...existingFacetValueIds, ...facetValueIds]);\r\n variantFormGroup.patchValue({\r\n facetValueIds: uniqueFacetValueIds,\r\n });\r\n variantFormGroup.markAsDirty();\r\n this.variantFacetValueChanges[variantId] = uniqueFacetValueIds;\r\n }\r\n }\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n variantsToCreateAreValid(): boolean {\r\n return (\r\n 0 < this.createVariantsConfig.variants.length &&\r\n this.createVariantsConfig.variants.every(v => {\r\n return v.sku !== '';\r\n })\r\n );\r\n }\r\n\r\n private displayFacetValueModal(): Observable<string[] | undefined> {\r\n return this.productDetailService.getFacets().pipe(\r\n mergeMap(facets =>\r\n this.modalService.fromComponent(ApplyFacetDialogComponent, {\r\n size: 'md',\r\n closable: true,\r\n locals: { facets },\r\n }),\r\n ),\r\n map(facetValues => facetValues && facetValues.map(v => v.id)),\r\n );\r\n }\r\n\r\n create() {\r\n const productGroup = this.getProductFormGroup();\r\n if (!productGroup.dirty) {\r\n return;\r\n }\r\n combineLatest(this.product$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode]) => {\r\n const newProduct = this.getUpdatedProduct(\r\n product,\r\n productGroup as FormGroup,\r\n languageCode,\r\n ) as CreateProductInput;\r\n return this.productDetailService.createProductWithVariants(\r\n newProduct,\r\n this.createVariantsConfig,\r\n languageCode,\r\n );\r\n }),\r\n )\r\n .subscribe(\r\n ({ createProductVariants, productId }) => {\r\n this.notificationService.success(_('common.notify-create-success'), {\r\n entity: 'Product',\r\n });\r\n this.assetChanges = {};\r\n this.variantAssetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.router.navigate(['../', productId], { relativeTo: this.route });\r\n },\r\n err => {\r\n // tslint:disable-next-line:no-console\r\n console.error(err);\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n combineLatest(this.product$, this.languageCode$, this.channelPriceIncludesTax$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([product, languageCode, priceIncludesTax]) => {\r\n const productGroup = this.getProductFormGroup();\r\n let productInput: UpdateProductInput | undefined;\r\n let variantsInput: UpdateProductVariantInput[] | undefined;\r\n\r\n if (productGroup.dirty || this.assetsChanged()) {\r\n productInput = this.getUpdatedProduct(\r\n product,\r\n productGroup as FormGroup,\r\n languageCode,\r\n ) as UpdateProductInput;\r\n }\r\n const variantsArray = this.detailForm.get('variants');\r\n if ((variantsArray && variantsArray.dirty) || this.variantAssetsChanged()) {\r\n variantsInput = this.getUpdatedProductVariants(\r\n product,\r\n variantsArray as FormArray,\r\n languageCode,\r\n priceIncludesTax,\r\n );\r\n }\r\n\r\n return this.productDetailService.updateProduct({\r\n product,\r\n languageCode,\r\n autoUpdate:\r\n this.detailForm.get(['product', 'autoUpdateVariantNames'])?.value ?? false,\r\n productInput,\r\n variantsInput,\r\n });\r\n }),\r\n )\r\n .subscribe(\r\n result => {\r\n this.updateSlugAfterSave(result);\r\n this.detailForm.markAsPristine();\r\n this.assetChanges = {};\r\n this.variantAssetChanges = {};\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'Product',\r\n });\r\n this.changeDetector.markForCheck();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return super.canDeactivate() && !this.assetChanges.assets && !this.assetChanges.featuredAsset;\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the product or current language.\r\n */\r\n protected setFormValues(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n languageCode: LanguageCode,\r\n ) {\r\n const currentTranslation = findTranslation(product, languageCode);\r\n this.detailForm.patchValue({\r\n product: {\r\n enabled: product.enabled,\r\n name: currentTranslation ? currentTranslation.name : '',\r\n slug: currentTranslation ? currentTranslation.slug : '',\r\n description: currentTranslation ? currentTranslation.description : '',\r\n facetValueIds: product.facetValues.map(fv => fv.id),\r\n },\r\n });\r\n\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['product', 'customFields']),\r\n product,\r\n currentTranslation,\r\n );\r\n }\r\n this.buildVariantFormArray(product.variantList.items, languageCode);\r\n }\r\n\r\n private buildVariantFormArray(variants: ProductVariantFragment[], languageCode: LanguageCode) {\r\n const variantsFormArray = this.detailForm.get('variants') as FormArray;\r\n variants.forEach((variant, i) => {\r\n const variantTranslation = findTranslation(variant, languageCode);\r\n const pendingFacetValueChanges = this.variantFacetValueChanges[variant.id];\r\n const facetValueIds = pendingFacetValueChanges\r\n ? pendingFacetValueChanges\r\n : variant.facetValues.map(fv => fv.id);\r\n const group: VariantFormValue = {\r\n id: variant.id,\r\n enabled: variant.enabled,\r\n sku: variant.sku,\r\n name: variantTranslation ? variantTranslation.name : '',\r\n price: variant.price,\r\n priceWithTax: variant.priceWithTax,\r\n taxCategoryId: variant.taxCategory.id,\r\n stockOnHand: variant.stockOnHand,\r\n useGlobalOutOfStockThreshold: variant.useGlobalOutOfStockThreshold,\r\n outOfStockThreshold: variant.outOfStockThreshold,\r\n trackInventory: variant.trackInventory,\r\n facetValueIds,\r\n };\r\n\r\n let variantFormGroup = variantsFormArray.controls.find(c => c.value.id === variant.id) as\r\n | FormGroup\r\n | undefined;\r\n if (variantFormGroup) {\r\n if (variantFormGroup.pristine) {\r\n variantFormGroup.patchValue(group);\r\n }\r\n } else {\r\n variantFormGroup = this.formBuilder.group({\r\n ...group,\r\n facetValueIds: this.formBuilder.control(facetValueIds),\r\n });\r\n variantsFormArray.insert(i, variantFormGroup);\r\n }\r\n if (this.customVariantFields.length) {\r\n let customFieldsGroup = variantFormGroup.get(['customFields']) as FormGroup | undefined;\r\n\r\n if (!customFieldsGroup) {\r\n customFieldsGroup = this.formBuilder.group(\r\n this.customVariantFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n );\r\n variantFormGroup.addControl('customFields', customFieldsGroup);\r\n }\r\n this.setCustomFieldFormValues(\r\n this.customVariantFields,\r\n customFieldsGroup,\r\n variant,\r\n variantTranslation,\r\n );\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Given a product and the value of the detailForm, this method creates an updated copy of the product which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedProduct(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n productFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductInput | CreateProductInput {\r\n const updatedProduct = createUpdatedTranslatable({\r\n translatable: product,\r\n updatedFields: productFormGroup.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: product.name || '',\r\n slug: product.slug || '',\r\n description: product.description || '',\r\n },\r\n });\r\n return {\r\n ...updatedProduct,\r\n assetIds: this.assetChanges.assets?.map(a => a.id),\r\n featuredAssetId: this.assetChanges.featuredAsset?.id,\r\n facetValueIds: productFormGroup.value.facetValueIds,\r\n } as UpdateProductInput | CreateProductInput;\r\n }\r\n\r\n /**\r\n * Given an array of product variants and the values from the detailForm, this method creates an new array\r\n * which can be persisted to the API.\r\n */\r\n private getUpdatedProductVariants(\r\n product: NonNullable<GetProductWithVariantsQuery['product']>,\r\n variantsFormArray: FormArray,\r\n languageCode: LanguageCode,\r\n priceIncludesTax: boolean,\r\n ): UpdateProductVariantInput[] {\r\n const dirtyFormControls = variantsFormArray.controls.filter(c => c.dirty);\r\n const dirtyVariants = dirtyFormControls\r\n .map(c => this.productVariantMap.get(c.value.id))\r\n .filter(notNullOrUndefined);\r\n const dirtyVariantValues = dirtyFormControls.map(c => c.value);\r\n\r\n if (dirtyVariants.length !== dirtyVariantValues.length) {\r\n throw new Error(_(`error.product-variant-form-values-do-not-match`));\r\n }\r\n return dirtyVariants\r\n .map((variant, i) => {\r\n const formValue: VariantFormValue = dirtyVariantValues.find(value => value.id === variant.id);\r\n const result: UpdateProductVariantInput = createUpdatedTranslatable({\r\n translatable: variant,\r\n updatedFields: formValue,\r\n customFieldConfig: this.customVariantFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: '',\r\n },\r\n });\r\n result.taxCategoryId = formValue.taxCategoryId;\r\n result.facetValueIds = formValue.facetValueIds;\r\n result.price = priceIncludesTax ? formValue.priceWithTax : formValue.price;\r\n const assetChanges = this.variantAssetChanges[variant.id];\r\n if (assetChanges) {\r\n result.featuredAssetId = assetChanges.featuredAsset?.id;\r\n result.assetIds = assetChanges.assets?.map(a => a.id);\r\n }\r\n return result;\r\n })\r\n .filter(notNullOrUndefined);\r\n }\r\n\r\n private getProductFormGroup(): FormGroup {\r\n return this.detailForm.get('product') as FormGroup;\r\n }\r\n\r\n /**\r\n * The server may alter the slug value in order to normalize and ensure uniqueness upon saving.\r\n */\r\n private updateSlugAfterSave(results: Array<UpdateProductMutation | UpdateProductVariantsMutation>) {\r\n const firstResult = results[0];\r\n const slugControl = this.detailForm.get(['product', 'slug']);\r\n\r\n function isUpdateMutation(input: any): input is UpdateProductMutation {\r\n return input.hasOwnProperty('updateProduct');\r\n }\r\n\r\n if (slugControl && isUpdateMutation(firstResult)) {\r\n slugControl.setValue(firstResult.updateProduct.slug, { emitEvent: false });\r\n }\r\n }\r\n}\r\n","<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","import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';\r\nimport { NgSelectComponent, SELECTION_MODEL_FACTORY } from '@ng-select/ng-select';\r\nimport { SearchProductsQuery, SingleSearchSelectionModelFactory } from '@vendure/admin-ui/core';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\n\r\ntype FacetValueResult = SearchProductsQuery['search']['facetValues'][number];\r\n\r\n@Component({\r\n selector: 'vdr-product-search-input',\r\n templateUrl: './product-search-input.component.html',\r\n styleUrls: ['./product-search-input.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [{ provide: SELECTION_MODEL_FACTORY, useValue: SingleSearchSelectionModelFactory }],\r\n})\r\nexport class ProductSearchInputComponent {\r\n @Input() facetValueResults: FacetValueResult;\r\n @Output() searchTermChange = new EventEmitter<string>();\r\n @Output() facetValueChange = new EventEmitter<string[]>();\r\n @ViewChild('selectComponent', { static: true }) private selectComponent: NgSelectComponent;\r\n private lastTerm = '';\r\n private lastFacetValueIds: string[] = [];\r\n\r\n setSearchTerm(term: string | null) {\r\n if (term) {\r\n this.selectComponent.select({ label: term, value: { label: term } });\r\n } else {\r\n const currentTerm = this.selectComponent.selectedItems.find(i => !this.isFacetValueItem(i.value));\r\n if (currentTerm) {\r\n this.selectComponent.unselect(currentTerm);\r\n }\r\n }\r\n }\r\n\r\n setFacetValues(ids: string[]) {\r\n const items = this.selectComponent.items;\r\n\r\n this.selectComponent.selectedItems.forEach(item => {\r\n if (this.isFacetValueItem(item.value) && !ids.includes(item.value.facetValue.id)) {\r\n this.selectComponent.unselect(item);\r\n }\r\n });\r\n\r\n ids.map(id => {\r\n return items?.find(item => this.isFacetValueItem(item) && item.facetValue.id === id);\r\n })\r\n .filter(notNullOrUndefined)\r\n .forEach(item => {\r\n const isSelected = this.selectComponent.selectedItems.find(i => {\r\n const val = i.value;\r\n if (this.isFacetValueItem(val)) {\r\n return val.facetValue.id === item.facetValue.id;\r\n }\r\n return false;\r\n });\r\n if (!isSelected) {\r\n this.selectComponent.select({ label: '', value: item });\r\n }\r\n });\r\n }\r\n\r\n filterFacetResults = (term: string, item: FacetValueResult | { label: string }) => {\r\n if (!this.isFacetValueItem(item)) {\r\n return false;\r\n }\r\n\r\n const cix = term.indexOf(':');\r\n const facetName = cix > -1 ? term.toLowerCase().slice(0, cix) : null;\r\n const facetVal = cix > -1 ? term.toLowerCase().slice(cix + 1) : term.toLowerCase();\r\n\r\n if (facetName) {\r\n return (\r\n item.facetValue.facet.name.toLowerCase().includes(facetName) &&\r\n item.facetValue.name.toLocaleLowerCase().includes(facetVal)\r\n );\r\n }\r\n\r\n return (\r\n item.facetValue.name.toLowerCase().includes(term.toLowerCase()) ||\r\n item.facetValue.facet.name.toLowerCase().includes(term.toLowerCase())\r\n );\r\n };\r\n\r\n onSelectChange(selectedItems: Array<FacetValueResult | { label: string }>) {\r\n if (!Array.isArray(selectedItems)) {\r\n selectedItems = [selectedItems];\r\n }\r\n const searchTermItem = selectedItems.find(item => !this.isFacetValueItem(item)) as\r\n | { label: string }\r\n | undefined;\r\n const searchTerm = searchTermItem ? searchTermItem.label : '';\r\n\r\n const facetValueIds = selectedItems.filter(this.isFacetValueItem).map(i => i.facetValue.id);\r\n\r\n if (searchTerm !== this.lastTerm) {\r\n this.searchTermChange.emit(searchTerm);\r\n this.lastTerm = searchTerm;\r\n }\r\n if (this.lastFacetValueIds.join(',') !== facetValueIds.join(',')) {\r\n this.facetValueChange.emit(facetValueIds);\r\n this.lastFacetValueIds = facetValueIds;\r\n }\r\n }\r\n\r\n addTagFn(item: any) {\r\n return { label: item };\r\n }\r\n\r\n isSearchHeaderSelected(): boolean {\r\n return this.selectComponent.itemsList.markedIndex === -1;\r\n }\r\n\r\n private isFacetValueItem = (input: unknown): input is FacetValueResult => {\r\n return typeof input === 'object' && !!input && input.hasOwnProperty('facetValue');\r\n };\r\n}\r\n","<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","import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n ItemOf,\r\n JobQueueService,\r\n JobState,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SearchInput,\r\n SearchProductsQuery,\r\n SearchProductsQueryVariables,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { delay, map, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';\r\n\r\nimport { ProductSearchInputComponent } from '../product-search-input/product-search-input.component';\r\n\r\n@Component({\r\n selector: 'vdr-products-list',\r\n templateUrl: './product-list.component.html',\r\n styleUrls: ['./product-list.component.scss'],\r\n})\r\nexport class ProductListComponent\r\n extends BaseListComponent<\r\n SearchProductsQuery,\r\n ItemOf<SearchProductsQuery, 'search'>,\r\n SearchProductsQueryVariables\r\n >\r\n implements OnInit, AfterViewInit\r\n{\r\n searchTerm = '';\r\n facetValueIds: string[] = [];\r\n groupByProduct = true;\r\n selectedFacetValueIds$: Observable<string[]>;\r\n facetValues$: Observable<SearchProductsQuery['search']['facetValues']>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n pendingSearchIndexUpdates = 0;\r\n\r\n @ViewChild('productSearchInputComponent', { static: true })\r\n private productSearchInput: ProductSearchInputComponent;\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private jobQueueService: JobQueueService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(term => {\r\n this.searchTerm = term || '';\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setSearchTerm(term);\r\n }\r\n });\r\n this.selectedFacetValueIds$ = this.route.queryParamMap.pipe(map(qpm => qpm.getAll('fvids')));\r\n\r\n this.selectedFacetValueIds$.pipe(takeUntil(this.destroy$)).subscribe(ids => {\r\n this.facetValueIds = ids;\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setFacetValues(ids);\r\n }\r\n });\r\n super.setQueryFn(\r\n (...args: any[]) =>\r\n this.dataService.product.searchProducts(this.searchTerm, ...args).refetchOnChannelChange(),\r\n data => data.search,\r\n // tslint:disable-next-line:no-shadowed-variable\r\n (skip, take) => ({\r\n input: {\r\n skip,\r\n take,\r\n term: this.searchTerm,\r\n facetValueIds: this.facetValueIds,\r\n facetValueOperator: LogicalOperator.AND,\r\n groupByProduct: this.groupByProduct,\r\n } as SearchInput,\r\n }),\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n\r\n this.facetValues$ = this.result$.pipe(map(data => data.search.facetValues));\r\n\r\n this.facetValues$\r\n .pipe(take(1), delay(100), withLatestFrom(this.selectedFacetValueIds$))\r\n .subscribe(([__, ids]) => {\r\n this.productSearchInput.setFacetValues(ids);\r\n });\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.dataService.product\r\n .getPendingSearchIndexUpdates()\r\n .mapSingle(({ pendingSearchIndexUpdates }) => pendingSearchIndexUpdates)\r\n .subscribe(value => (this.pendingSearchIndexUpdates = value));\r\n }\r\n\r\n ngAfterViewInit() {\r\n if (this.productSearchInput && this.searchTerm) {\r\n setTimeout(() => this.productSearchInput.setSearchTerm(this.searchTerm));\r\n }\r\n }\r\n\r\n setSearchTerm(term: string) {\r\n this.searchTerm = term;\r\n this.setQueryParam({ q: term || null, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n setFacetValueIds(ids: string[]) {\r\n this.facetValueIds = ids;\r\n this.setQueryParam({ fvids: ids, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n rebuildSearchIndex() {\r\n this.dataService.product.reindex().subscribe(({ reindex }) => {\r\n this.notificationService.info(_('catalog.reindexing'));\r\n this.jobQueueService.addJob(reindex.id, job => {\r\n if (job.state === JobState.COMPLETED) {\r\n const time = new Intl.NumberFormat().format(job.duration || 0);\r\n this.notificationService.success(_('catalog.reindex-successful'), {\r\n count: job.result.indexedItemCount,\r\n time,\r\n });\r\n this.refresh();\r\n } else {\r\n this.notificationService.error(_('catalog.reindex-error'));\r\n }\r\n });\r\n });\r\n }\r\n\r\n runPendingSearchIndexUpdates() {\r\n this.dataService.product.runPendingSearchIndexUpdates().subscribe(value => {\r\n this.notificationService.info(_('catalog.running-search-index-updates'), {\r\n count: this.pendingSearchIndexUpdates,\r\n });\r\n this.pendingSearchIndexUpdates = 0;\r\n });\r\n }\r\n\r\n deleteProduct(productId: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),\r\n // Short delay to allow the product to be removed from the search index before\r\n // refreshing.\r\n delay(500),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Product',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-language-selector\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 <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n [(ngModel)]=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{ 'catalog.auto-update-product-variant-name' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.pristine || detailForm.invalid\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </div>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"optionGroups$ | async as optionGroups\">\r\n <div formGroupName=\"optionGroups\" class=\"clr-row\">\r\n <div class=\"clr-col-12 clr-col-xl-6\" *ngFor=\"let optionGroup of getOptionGroups(); index as i\">\r\n <section class=\"card\" [formArrayName]=\"i\">\r\n <div class=\"card-header option-group-header\">\r\n <vdr-entity-info [entity]=\"optionGroup.value\"></vdr-entity-info>\r\n <div class=\"ml2\">{{ optionGroup.value.code }}</div>\r\n </div>\r\n <div class=\"card-block\">\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n [id]=\"'name-' + i\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input\r\n [id]=\"'code-' + i\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n </div>\r\n <section class=\"card-block\">\r\n <table class=\"facet-values-list table mt2 mb4\" formGroupName=\"options\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n class=\"facet-value\"\r\n *ngFor=\"let option of getOptions(optionGroup); let i = index\"\r\n [formGroupName]=\"i\"\r\n >\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"option.value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" /></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </section>\r\n </section>\r\n </div>\r\n </div>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n findTranslation,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n NotificationService,\r\n Permission,\r\n ProductOptionFragment,\r\n ProductOptionGroup,\r\n ProductOptionGroupFragment,\r\n ServerConfigService,\r\n UpdateProductOptionGroupInput,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, forkJoin, Observable } from 'rxjs';\r\nimport { map, mergeMap, take } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\n\r\ntype ProductWithOptions = NonNullable<GetProductVariantOptionsQuery['product']>;\r\n\r\n@Component({\r\n selector: 'vdr-product-options-editor',\r\n templateUrl: './product-options-editor.component.html',\r\n styleUrls: ['./product-options-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductOptionsEditorComponent extends BaseDetailComponent<ProductWithOptions> implements OnInit {\r\n detailForm: FormGroup;\r\n optionGroups$: Observable<ProductWithOptions['optionGroups']>;\r\n languageCode$: Observable<LanguageCode>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n optionGroupCustomFields: CustomFieldConfig[];\r\n optionCustomFields: CustomFieldConfig[];\r\n autoUpdateVariantNames = true;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n protected route: ActivatedRoute,\r\n protected router: Router,\r\n protected serverConfigService: ServerConfigService,\r\n protected dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private changeDetector: ChangeDetectorRef,\r\n private notificationService: NotificationService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.optionGroupCustomFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.optionCustomFields = this.getCustomFieldConfig('ProductOption');\r\n }\r\n\r\n ngOnInit(): void {\r\n this.optionGroups$ = this.route.snapshot.data.entity.pipe(\r\n map((product: ProductWithOptions) => product.optionGroups),\r\n );\r\n this.detailForm = new FormGroup({\r\n optionGroups: new FormArray([]),\r\n });\r\n super.init();\r\n }\r\n\r\n getOptionGroups(): FormGroup[] {\r\n const optionGroups = this.detailForm.get('optionGroups');\r\n return (optionGroups as FormArray).controls as FormGroup[];\r\n }\r\n\r\n getOptions(optionGroup: FormGroup): FormGroup[] {\r\n const options = optionGroup.get('options');\r\n return (options as FormArray).controls as FormGroup[];\r\n }\r\n\r\n save() {\r\n if (this.detailForm.invalid || this.detailForm.pristine) {\r\n return;\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const $product = this.dataService.product.getProduct(this.id).mapSingle(data => data.product!);\r\n combineLatest(this.entity$, this.languageCode$, $product)\r\n .pipe(\r\n take(1),\r\n mergeMap(([{ optionGroups }, languageCode, product]) => {\r\n const updateOperations: Array<Observable<any>> = [];\r\n for (const optionGroupForm of this.getOptionGroups()) {\r\n if (optionGroupForm.get('name')?.dirty || optionGroupForm.get('code')?.dirty) {\r\n const optionGroupEntity = optionGroups.find(\r\n og => og.id === optionGroupForm.value.id,\r\n );\r\n if (optionGroupEntity) {\r\n const input = this.getUpdatedOptionGroup(\r\n optionGroupEntity,\r\n optionGroupForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.dataService.product.updateProductOptionGroup(input),\r\n );\r\n }\r\n }\r\n\r\n for (const optionForm of this.getOptions(optionGroupForm)) {\r\n if (optionForm.get('name')?.dirty || optionForm.get('code')?.dirty) {\r\n const optionGroup = optionGroups\r\n .find(og => og.id === optionGroupForm.value.id)\r\n ?.options.find(o => o.id === optionForm.value.id);\r\n if (optionGroup) {\r\n const input = this.getUpdatedOption(\r\n optionGroup,\r\n optionForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.productDetailService.updateProductOption(\r\n { ...input, autoUpdate: this.autoUpdateVariantNames },\r\n product,\r\n languageCode,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private getUpdatedOptionGroup(\r\n optionGroup: ProductOptionGroupFragment,\r\n optionGroupFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionGroupInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: optionGroup,\r\n updatedFields: optionGroupFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: optionGroup.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n private getUpdatedOption(\r\n option: ProductOptionFragment,\r\n optionFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: option,\r\n updatedFields: optionFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: option.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n protected setFormValues(entity: ProductWithOptions, languageCode: LanguageCode): void {\r\n const groupsFormArray = new FormArray([]);\r\n for (const optionGroup of entity.optionGroups) {\r\n const groupTranslation = findTranslation(optionGroup, languageCode);\r\n const group = {\r\n id: optionGroup.id,\r\n createdAt: optionGroup.createdAt,\r\n updatedAt: optionGroup.updatedAt,\r\n code: optionGroup.code,\r\n name: groupTranslation ? groupTranslation.name : '',\r\n };\r\n const optionsFormArray = new FormArray([]);\r\n\r\n for (const option of optionGroup.options) {\r\n const optionTranslation = findTranslation(option, languageCode);\r\n const optionControl = this.formBuilder.group({\r\n id: option.id,\r\n createdAt: option.createdAt,\r\n updatedAt: option.updatedAt,\r\n code: option.code,\r\n name: optionTranslation ? optionTranslation.name : '',\r\n });\r\n optionsFormArray.push(optionControl);\r\n }\r\n\r\n const groupControl = this.formBuilder.group(group);\r\n groupControl.addControl('options', optionsFormArray);\r\n groupsFormArray.push(groupControl);\r\n }\r\n this.detailForm.setControl('optionGroups', groupsFormArray);\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.confirm-deletion-of-unused-variants-title' | translate }}\r\n</ng-template>\r\n{{ 'catalog.confirm-deletion-of-unused-variants-body' | translate }}\r\n<ul>\r\n <li *ngFor=\"let variant of variants\">{{ variant.name }} ({{ variant.sku }})</li>\r\n</ul>\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"confirm()\" class=\"btn btn-primary\">\r\n {{ 'common.confirm' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { Dialog, GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-confirm-variant-deletion-dialog',\r\n templateUrl: './confirm-variant-deletion-dialog.component.html',\r\n styleUrls: ['./confirm-variant-deletion-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ConfirmVariantDeletionDialogComponent implements Dialog<boolean> {\r\n resolveWith: (result?: boolean) => void;\r\n variants: NonNullable<GetProductVariantOptionsQuery['product']>['variants'] = [];\r\n\r\n confirm() {\r\n this.resolveWith(true);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"!formValueChanged || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n</div>\r\n<button\r\n class=\"btn btn-primary-outline btn-sm\"\r\n (click)=\"addOption()\"\r\n>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.create' | translate }}</th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n *ngIf=\"!variant.existing\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n CreateProductOptionGroupMutation,\r\n CreateProductOptionInput,\r\n CurrencyCode,\r\n DataService,\r\n DeactivateAware,\r\n getDefaultUiLanguage,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n ProductOptionGroupWithOptionsFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { pick } from '@vendure/common/lib/pick';\r\nimport { generateAllCombinations, notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, forkJoin, Observable, of } from 'rxjs';\r\nimport { filter, map, mergeMap, switchMap } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ConfirmVariantDeletionDialogComponent } from '../confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\n\r\nexport class GeneratedVariant {\r\n isDefault: boolean;\r\n options: Array<{ name: string; id?: string }>;\r\n productVariantId?: string;\r\n enabled: boolean;\r\n existing: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n\r\n constructor(config: Partial<GeneratedVariant>) {\r\n for (const key of Object.keys(config)) {\r\n this[key] = config[key];\r\n }\r\n }\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-editor',\r\n templateUrl: './product-variants-editor.component.html',\r\n styleUrls: ['./product-variants-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n})\r\nexport class ProductVariantsEditorComponent implements OnInit, DeactivateAware {\r\n formValueChanged = false;\r\n generatedVariants: GeneratedVariant[] = [];\r\n optionGroups: Array<{\r\n id?: string;\r\n isNew: boolean;\r\n name: string;\r\n values: Array<{\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n }>;\r\n }>;\r\n product: NonNullable<GetProductVariantOptionsQuery['product']>;\r\n currencyCode: CurrencyCode;\r\n private languageCode: LanguageCode;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.initOptionsAndVariants();\r\n this.languageCode =\r\n (this.route.snapshot.paramMap.get('lang') as LanguageCode) || getDefaultUiLanguage();\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n }\r\n\r\n onFormChanged(variantInfo: GeneratedVariant) {\r\n this.formValueChanged = true;\r\n variantInfo.enabled = true;\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return !this.formValueChanged;\r\n }\r\n\r\n getVariantsToAdd() {\r\n return this.generatedVariants.filter(v => !v.existing && v.enabled);\r\n }\r\n\r\n getVariantName(variant: GeneratedVariant) {\r\n return variant.options.length === 0\r\n ? _('catalog.default-variant')\r\n : variant.options.map(o => o.name).join(' ');\r\n }\r\n\r\n addOption() {\r\n this.optionGroups.push({\r\n isNew: true,\r\n name: '',\r\n values: [],\r\n });\r\n }\r\n\r\n generateVariants() {\r\n const groups = this.optionGroups.map(g => g.values);\r\n const previousVariants = this.generatedVariants;\r\n const generatedVariantFactory = (\r\n isDefault: boolean,\r\n options: GeneratedVariant['options'],\r\n existingVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n prototypeVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n ): GeneratedVariant => {\r\n const prototype = this.getVariantPrototype(options, previousVariants);\r\n return new GeneratedVariant({\r\n enabled: true,\r\n existing: !!existingVariant,\r\n productVariantId: existingVariant?.id,\r\n isDefault,\r\n options,\r\n price: existingVariant?.price ?? prototypeVariant?.price ?? prototype.price,\r\n sku: existingVariant?.sku ?? prototypeVariant?.sku ?? prototype.sku,\r\n stock: existingVariant?.stockOnHand ?? prototypeVariant?.stockOnHand ?? prototype.stock,\r\n });\r\n };\r\n this.generatedVariants = groups.length\r\n ? generateAllCombinations(groups).map(options => {\r\n const existingVariant = this.product.variants.find(v =>\r\n this.optionsAreEqual(v.options, options),\r\n );\r\n const prototypeVariant = this.product.variants.find(v =>\r\n this.optionsAreSubset(v.options, options),\r\n );\r\n return generatedVariantFactory(false, options, existingVariant, prototypeVariant);\r\n })\r\n : [generatedVariantFactory(true, [], this.product.variants[0])];\r\n }\r\n\r\n /**\r\n * Returns one of the existing variants to base the newly-generated variant's\r\n * details off.\r\n */\r\n private getVariantPrototype(\r\n options: GeneratedVariant['options'],\r\n previousVariants: GeneratedVariant[],\r\n ): Pick<GeneratedVariant, 'sku' | 'price' | 'stock'> {\r\n const variantsWithSimilarOptions = previousVariants.filter(v =>\r\n options.map(o => o.name).filter(name => v.options.map(o => o.name).includes(name)),\r\n );\r\n if (variantsWithSimilarOptions.length) {\r\n return pick(previousVariants[0], ['sku', 'price', 'stock']);\r\n }\r\n return {\r\n sku: '',\r\n price: 0,\r\n stock: 0,\r\n };\r\n }\r\n\r\n deleteVariant(id: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-variant'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response ? this.productDetailService.deleteProductVariant(id, this.product.id) : EMPTY,\r\n ),\r\n switchMap(() => this.reFetchProduct(null)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductVariant',\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'ProductVariant',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n const newOptionGroups = this.optionGroups\r\n .filter(og => og.isNew)\r\n .map(og => ({\r\n name: og.name,\r\n values: [],\r\n }));\r\n\r\n this.checkUniqueSkus()\r\n .pipe(\r\n mergeMap(() => this.confirmDeletionOfObsoleteVariants()),\r\n mergeMap(() =>\r\n this.productDetailService.createProductOptionGroups(newOptionGroups, this.languageCode),\r\n ),\r\n mergeMap(createdOptionGroups => this.addOptionGroupsToProduct(createdOptionGroups)),\r\n mergeMap(createdOptionGroups => this.addNewOptionsToGroups(createdOptionGroups)),\r\n mergeMap(groupsIds => this.fetchOptionGroups(groupsIds)),\r\n mergeMap(groups => this.createNewProductVariants(groups)),\r\n mergeMap(res => this.deleteObsoleteVariants(res.createProductVariants)),\r\n mergeMap(variants => this.reFetchProduct(variants)),\r\n )\r\n .subscribe({\r\n next: variants => {\r\n this.formValueChanged = false;\r\n this.notificationService.success(_('catalog.created-new-variants-success'), {\r\n count: variants.length,\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n });\r\n }\r\n\r\n private checkUniqueSkus() {\r\n const withDuplicateSkus = this.generatedVariants.filter((variant, index) => {\r\n return this.generatedVariants.find(gv => gv.sku.trim() === variant.sku.trim() && gv !== variant);\r\n });\r\n if (withDuplicateSkus.length) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.duplicate-sku-warning'),\r\n body: unique(withDuplicateSkus.map(v => `${v.sku}`)).join(', '),\r\n buttons: [{ label: _('common.close'), returnValue: false, type: 'primary' }],\r\n })\r\n .pipe(mergeMap(res => EMPTY));\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private confirmDeletionOfObsoleteVariants(): Observable<boolean> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n return this.modalService\r\n .fromComponent(ConfirmVariantDeletionDialogComponent, {\r\n locals: {\r\n variants: obsoleteVariants,\r\n },\r\n })\r\n .pipe(\r\n mergeMap(res => {\r\n return res === true ? of(true) : EMPTY;\r\n }),\r\n );\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private getObsoleteVariants() {\r\n return this.product.variants.filter(\r\n variant => !this.generatedVariants.find(gv => gv.productVariantId === variant.id),\r\n );\r\n }\r\n\r\n private hasOnlyDefaultVariant(product: NonNullable<GetProductVariantOptionsQuery['product']>): boolean {\r\n return product.variants.length === 1 && product.optionGroups.length === 0;\r\n }\r\n\r\n private addOptionGroupsToProduct(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<Array<CreateProductOptionGroupMutation['createProductOptionGroup']>> {\r\n if (createdOptionGroups.length) {\r\n return forkJoin(\r\n createdOptionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: this.product.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n ).pipe(map(() => createdOptionGroups));\r\n } else {\r\n return of([]);\r\n }\r\n }\r\n\r\n private addNewOptionsToGroups(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<string[]> {\r\n const newOptions: CreateProductOptionInput[] = this.optionGroups\r\n .map(og => {\r\n const createdGroup = createdOptionGroups.find(cog => cog.name === og.name);\r\n const productOptionGroupId = createdGroup ? createdGroup.id : og.id;\r\n if (!productOptionGroupId) {\r\n throw new Error('Could not get a productOptionGroupId');\r\n }\r\n return og.values\r\n .filter(v => !v.locked)\r\n .map(v => ({\r\n productOptionGroupId,\r\n code: normalizeString(v.name, '-'),\r\n translations: [{ name: v.name, languageCode: this.languageCode }],\r\n }));\r\n })\r\n .reduce((flat, options) => [...flat, ...options], []);\r\n\r\n const allGroupIds = [\r\n ...createdOptionGroups.map(g => g.id),\r\n ...this.optionGroups.map(g => g.id).filter(notNullOrUndefined),\r\n ];\r\n\r\n if (newOptions.length) {\r\n return forkJoin(newOptions.map(input => this.dataService.product.addOptionToGroup(input))).pipe(\r\n map(() => allGroupIds),\r\n );\r\n } else {\r\n return of(allGroupIds);\r\n }\r\n }\r\n\r\n private fetchOptionGroups(groupsIds: string[]): Observable<ProductOptionGroupWithOptionsFragment[]> {\r\n return forkJoin(\r\n groupsIds.map(id =>\r\n this.dataService.product\r\n .getProductOptionGroup(id)\r\n .mapSingle(data => data.productOptionGroup)\r\n .pipe(filter(notNullOrUndefined)),\r\n ),\r\n );\r\n }\r\n\r\n private createNewProductVariants(groups: ProductOptionGroupWithOptionsFragment[]) {\r\n const options = groups\r\n .filter(notNullOrUndefined)\r\n .map(og => og.options)\r\n .reduce((flat, o) => [...flat, ...o], []);\r\n const variants = this.generatedVariants\r\n .filter(v => v.enabled && !v.existing)\r\n .map(v => ({\r\n price: v.price,\r\n sku: v.sku,\r\n stock: v.stock,\r\n optionIds: v.options\r\n .map(name => options.find(o => o.name === name.name))\r\n .filter(notNullOrUndefined)\r\n .map(o => o.id),\r\n }));\r\n return this.productDetailService.createProductVariants(\r\n this.product,\r\n variants,\r\n options,\r\n this.languageCode,\r\n );\r\n }\r\n\r\n private deleteObsoleteVariants<T>(input: T): Observable<T | T[]> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n const deleteOperations = obsoleteVariants.map(v =>\r\n this.dataService.product.deleteProductVariant(v.id).pipe(map(() => input)),\r\n );\r\n return forkJoin(...deleteOperations);\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n private reFetchProduct<T>(input: T): Observable<T> {\r\n // Re-fetch the Product to force an update to the view.\r\n const id = this.route.snapshot.paramMap.get('id');\r\n if (id) {\r\n return this.dataService.product.getProduct(id).single$.pipe(map(() => input));\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n initOptionsAndVariants() {\r\n this.dataService.product\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .getProductVariantsOptions(this.route.snapshot.paramMap.get('id')!)\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .mapSingle(({ product }) => product!)\r\n .subscribe(p => {\r\n this.product = p;\r\n this.optionGroups = p.optionGroups.map(og => {\r\n return {\r\n id: og.id,\r\n isNew: false,\r\n name: og.name,\r\n values: og.options.map(o => ({\r\n id: o.id,\r\n name: o.name,\r\n locked: true,\r\n })),\r\n };\r\n });\r\n this.generateVariants();\r\n });\r\n }\r\n\r\n private optionsAreEqual(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(a) === this.toOptionString(b);\r\n }\r\n\r\n private optionsAreSubset(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(b).includes(this.toOptionString(a));\r\n }\r\n\r\n private toOptionString(o: Array<{ name: string }>): string {\r\n return o\r\n .map(x => x.name)\r\n .sort()\r\n .join('|');\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AssetFragment, AssetType, BaseEntityResolver, DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class AssetResolver extends BaseEntityResolver<AssetFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Asset' as const,\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n type: AssetType.IMAGE,\r\n fileSize: 0,\r\n mimeType: '',\r\n width: 0,\r\n height: 0,\r\n source: '',\r\n preview: '',\r\n focalPoint: null,\r\n },\r\n id => dataService.product.getAsset(id).mapStream(data => data.asset),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\nimport { Router } from '@angular/router';\nimport {\n BaseEntityResolver,\n CollectionFragment,\n DataService,\n getDefaultUiLanguage,\n} from '@vendure/admin-ui/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class CollectionResolver extends BaseEntityResolver<CollectionFragment> {\n constructor(router: Router, dataService: DataService) {\n super(\n router,\n {\n __typename: 'Collection' as 'Collection',\n id: '',\n createdAt: '',\n updatedAt: '',\n languageCode: getDefaultUiLanguage(),\n name: '',\n slug: '',\n isPrivate: false,\n description: '',\n featuredAsset: null,\n assets: [],\n translations: [],\n inheritFilters: true,\n filters: [],\n parent: {} as any,\n children: null,\n },\n id => dataService.collection.getCollection(id).mapStream(data => data.collection),\n );\n }\n}\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n FacetWithValuesFragment,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class FacetResolver extends BaseEntityResolver<FacetWithValuesFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Facet' as 'Facet',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n isPrivate: false,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n code: '',\r\n translations: [],\r\n values: [],\r\n },\r\n id => dataService.facet.getFacet(id).mapStream(data => data.facet),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n DataService,\r\n getDefaultUiLanguage,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductResolver extends BaseEntityResolver<GetProductWithVariantsQuery['product']> {\r\n constructor(dataService: DataService, router: Router) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n enabled: true,\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n featuredAsset: null,\r\n assets: [],\r\n description: '',\r\n translations: [],\r\n optionGroups: [],\r\n facetValues: [],\r\n variantList: { items: [], totalItems: 0 },\r\n channels: [],\r\n },\r\n id =>\r\n dataService.product\r\n .getProduct(id, { take: 10 })\r\n .refetchOnChannelChange()\r\n .mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { BaseEntityResolver } from '@vendure/admin-ui/core';\r\nimport { GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\nimport { DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ProductVariantsResolver extends BaseEntityResolver<GetProductVariantOptionsQuery['product']> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Product' as 'Product',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n optionGroups: [],\r\n variants: [],\r\n },\r\n id => dataService.product.getProductVariantsOptions(id).mapStream(data => data.product),\r\n );\r\n }\r\n}\r\n","import { Route } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n AssetFragment,\r\n CanDeactivateDetailGuard,\r\n CollectionFragment,\r\n createResolveData,\r\n detailBreadcrumb,\r\n FacetWithValuesFragment,\r\n GetProductWithVariantsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { map } from 'rxjs/operators';\r\n\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { AssetResolver } from './providers/routing/asset-resolver';\r\nimport { CollectionResolver } from './providers/routing/collection-resolver';\r\nimport { FacetResolver } from './providers/routing/facet-resolver';\r\nimport { ProductResolver } from './providers/routing/product-resolver';\r\nimport { ProductVariantsResolver } from './providers/routing/product-variants-resolver';\r\n\r\nexport const catalogRoutes: Route[] = [\r\n {\r\n path: 'products',\r\n component: ProductListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.products'),\r\n },\r\n },\r\n {\r\n path: 'products/:id',\r\n component: ProductDetailComponent,\r\n resolve: createResolveData(ProductResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/manage-variants',\r\n component: ProductVariantsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productVariantEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'products/:id/options',\r\n component: ProductOptionsEditorComponent,\r\n resolve: createResolveData(ProductVariantsResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: productOptionsEditorBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'facets',\r\n component: FacetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.facets'),\r\n },\r\n },\r\n {\r\n path: 'facets/:id',\r\n component: FacetDetailComponent,\r\n resolve: createResolveData(FacetResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: facetBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'collections',\r\n component: CollectionListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.collections'),\r\n },\r\n },\r\n {\r\n path: 'collections/:id',\r\n component: CollectionDetailComponent,\r\n resolve: createResolveData(CollectionResolver),\r\n canDeactivate: [CanDeactivateDetailGuard],\r\n data: {\r\n breadcrumb: collectionBreadcrumb,\r\n },\r\n },\r\n {\r\n path: 'assets',\r\n component: AssetListComponent,\r\n data: {\r\n breadcrumb: _('breadcrumb.assets'),\r\n },\r\n },\r\n {\r\n path: 'assets/:id',\r\n component: AssetDetailComponent,\r\n resolve: createResolveData(AssetResolver),\r\n data: {\r\n breadcrumb: assetBreadcrumb,\r\n },\r\n },\r\n];\r\n\r\nexport function productBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<NonNullable<GetProductWithVariantsQuery['product']>>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.products',\r\n getName: product => product.name,\r\n route: 'products',\r\n });\r\n}\r\n\r\nexport function productVariantEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.manage-variants'),\r\n link: ['manage-variants'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function productOptionsEditorBreadcrumb(data: any, params: any) {\r\n return data.entity.pipe(\r\n map((entity: any) => {\r\n return [\r\n {\r\n label: _('breadcrumb.products'),\r\n link: ['../', 'products'],\r\n },\r\n {\r\n label: `${entity.name}`,\r\n link: ['../', 'products', params.id, { tab: 'variants' }],\r\n },\r\n {\r\n label: _('breadcrumb.product-options'),\r\n link: ['options'],\r\n },\r\n ];\r\n }),\r\n );\r\n}\r\n\r\nexport function facetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<FacetWithValuesFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.facets',\r\n getName: facet => facet.name,\r\n route: 'facets',\r\n });\r\n}\r\n\r\nexport function collectionBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<CollectionFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.collections',\r\n getName: collection => collection.name,\r\n route: 'collections',\r\n });\r\n}\r\n\r\nexport function assetBreadcrumb(data: any, params: any) {\r\n return detailBreadcrumb<AssetFragment>({\r\n entity: data.entity,\r\n id: params.id,\r\n breadcrumbKey: 'breadcrumb.assets',\r\n getName: asset => asset.name,\r\n route: 'assets',\r\n });\r\n}\r\n","import { NgModule } from '@angular/core';\r\nimport { RouterModule } from '@angular/router';\r\nimport { SharedModule } from '@vendure/admin-ui/core';\r\n\r\nimport { catalogRoutes } from './catalog.routes';\r\nimport { ApplyFacetDialogComponent } from './components/apply-facet-dialog/apply-facet-dialog.component';\r\nimport { AssetDetailComponent } from './components/asset-detail/asset-detail.component';\r\nimport { AssetListComponent } from './components/asset-list/asset-list.component';\r\nimport { AssetsComponent } from './components/assets/assets.component';\r\nimport { AssignProductsToChannelDialogComponent } from './components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';\r\nimport { CollectionContentsComponent } from './components/collection-contents/collection-contents.component';\r\nimport { CollectionDetailComponent } from './components/collection-detail/collection-detail.component';\r\nimport { CollectionListComponent } from './components/collection-list/collection-list.component';\r\nimport { CollectionTreeNodeComponent } from './components/collection-tree/collection-tree-node.component';\r\nimport { CollectionTreeComponent } from './components/collection-tree/collection-tree.component';\r\nimport { ConfirmVariantDeletionDialogComponent } from './components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\nimport { FacetDetailComponent } from './components/facet-detail/facet-detail.component';\r\nimport { FacetListComponent } from './components/facet-list/facet-list.component';\r\nimport { GenerateProductVariantsComponent } from './components/generate-product-variants/generate-product-variants.component';\r\nimport { OptionValueInputComponent } from './components/option-value-input/option-value-input.component';\r\nimport { ProductDetailComponent } from './components/product-detail/product-detail.component';\r\nimport { ProductListComponent } from './components/product-list/product-list.component';\r\nimport { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';\r\nimport { ProductSearchInputComponent } from './components/product-search-input/product-search-input.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { ProductVariantsListComponent } from './components/product-variants-list/product-variants-list.component';\r\nimport { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';\r\nimport { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';\r\nimport { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';\r\n\r\nconst CATALOG_COMPONENTS = [\r\n ProductListComponent,\r\n ProductDetailComponent,\r\n FacetListComponent,\r\n FacetDetailComponent,\r\n GenerateProductVariantsComponent,\r\n ProductVariantsListComponent,\r\n ApplyFacetDialogComponent,\r\n AssetListComponent,\r\n AssetsComponent,\r\n VariantPriceDetailComponent,\r\n CollectionListComponent,\r\n CollectionDetailComponent,\r\n CollectionTreeComponent,\r\n CollectionTreeNodeComponent,\r\n CollectionContentsComponent,\r\n ProductVariantsTableComponent,\r\n ProductSearchInputComponent,\r\n OptionValueInputComponent,\r\n UpdateProductOptionDialogComponent,\r\n ProductVariantsEditorComponent,\r\n AssignProductsToChannelDialogComponent,\r\n AssetDetailComponent,\r\n ConfirmVariantDeletionDialogComponent,\r\n ProductOptionsEditorComponent,\r\n];\r\n\r\n@NgModule({\r\n imports: [SharedModule, RouterModule.forChild(catalogRoutes)],\r\n exports: [...CATALOG_COMPONENTS],\r\n declarations: [...CATALOG_COMPONENTS],\r\n})\r\nexport class CatalogModule {}\r\n"],"sourceRoot":"webpack:///","file":"349.abe4847f7fe9b3da.js"}
|