@vendure/admin-ui-plugin 2.0.0-next.10 → 2.0.0-next.13
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.68785500c3346bfc.js → 239.ca7af610928bd44b.js} +2 -2
- package/lib/admin-ui/{239.68785500c3346bfc.js.map → 239.ca7af610928bd44b.js.map} +1 -1
- package/lib/admin-ui/{26.f714c21768111b4f.js → 26.762a61e2d3e37e33.js} +2 -2
- package/lib/admin-ui/{26.f714c21768111b4f.js.map → 26.762a61e2d3e37e33.js.map} +1 -1
- package/lib/admin-ui/{316.f5c3548835a302f3.js → 316.fbaa08dea0a8bad5.js} +2 -2
- package/lib/admin-ui/{316.f5c3548835a302f3.js.map → 316.fbaa08dea0a8bad5.js.map} +1 -1
- package/lib/admin-ui/{356.d5ab46db919a9f0b.js → 356.0ff226e8c9164ae6.js} +2 -2
- package/lib/admin-ui/{356.d5ab46db919a9f0b.js.map → 356.0ff226e8c9164ae6.js.map} +1 -1
- package/lib/admin-ui/3rdpartylicenses.txt +23 -0
- package/lib/admin-ui/504.40693d5cedca9d79.js +2 -0
- package/lib/admin-ui/504.40693d5cedca9d79.js.map +1 -0
- package/lib/admin-ui/600.fa2fa923a1a62838.js +2 -0
- package/lib/admin-ui/600.fa2fa923a1a62838.js.map +1 -0
- package/lib/admin-ui/{625.00b1380b31501047.js → 625.ed9ce3bf64237de8.js} +2 -2
- package/lib/admin-ui/{625.00b1380b31501047.js.map → 625.ed9ce3bf64237de8.js.map} +1 -1
- package/lib/admin-ui/849.21d37348d17a9559.js +2 -0
- package/lib/admin-ui/849.21d37348d17a9559.js.map +1 -0
- package/lib/admin-ui/i18n-messages/cs.json +6 -3
- package/lib/admin-ui/i18n-messages/de.json +6 -3
- package/lib/admin-ui/i18n-messages/en.json +7 -3
- package/lib/admin-ui/i18n-messages/es.json +6 -3
- package/lib/admin-ui/i18n-messages/fr.json +6 -3
- package/lib/admin-ui/i18n-messages/it.json +6 -3
- package/lib/admin-ui/i18n-messages/pl.json +6 -3
- package/lib/admin-ui/i18n-messages/pt_BR.json +6 -3
- package/lib/admin-ui/i18n-messages/pt_PT.json +6 -3
- package/lib/admin-ui/i18n-messages/ru.json +6 -3
- package/lib/admin-ui/i18n-messages/uk.json +6 -3
- package/lib/admin-ui/i18n-messages/zh_Hans.json +6 -3
- package/lib/admin-ui/i18n-messages/zh_Hant.json +6 -3
- package/lib/admin-ui/index.html +2 -2
- package/lib/admin-ui/main.5b576260330cb630.js +2777 -0
- package/lib/admin-ui/main.5b576260330cb630.js.map +1 -0
- package/lib/admin-ui/{runtime.7f595bf374c7bfaa.js → runtime.6ba91bceea486bae.js} +2 -2
- package/lib/admin-ui/{runtime.7f595bf374c7bfaa.js.map → runtime.6ba91bceea486bae.js.map} +1 -1
- package/lib/admin-ui/styles/_variables.scss +3 -0
- package/lib/admin-ui/styles/global/_sass-overrides.scss +3 -0
- package/lib/admin-ui/styles/global/_utilities.scss +1 -0
- package/lib/admin-ui/styles/styles.scss +1 -0
- package/lib/admin-ui/styles/ui-extension-theme.scss +1 -0
- package/lib/admin-ui/{styles.4e29f263e5259cf7.css → styles.8bb62235b8640049.css} +2 -2
- package/lib/admin-ui/styles.8bb62235b8640049.css.map +1 -0
- package/package.json +4 -4
- package/lib/admin-ui/504.56537eeeb3db51b7.js +0 -2
- package/lib/admin-ui/504.56537eeeb3db51b7.js.map +0 -1
- package/lib/admin-ui/600.e304581e252828a2.js +0 -2
- package/lib/admin-ui/600.e304581e252828a2.js.map +0 -1
- package/lib/admin-ui/849.f649a9ff8824afb1.js +0 -2
- package/lib/admin-ui/849.f649a9ff8824afb1.js.map +0 -1
- package/lib/admin-ui/main.6bcd8b4a17724f1f.js +0 -2758
- package/lib/admin-ui/main.6bcd8b4a17724f1f.js.map +0 -1
- package/lib/admin-ui/styles.4e29f263e5259cf7.css.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["t","save","c","constructor","n","e","o","a","r","s","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","nt","selectors","U","setQueryFn","getAssetList","assets","d","f","searchTerm$","m","p","filterByTags$","map","g","options","skip","take","filter","contains","sort","createdAt","tagsOperator","paginationConfig$","itemsPerPage$","currentPage$","totalItems$","pipe","v","itemsPerPage","currentPage","totalItems","destroy$","refresh","allTags$","getTagList","mapStream","items","filesSelected","uploading","createAssets","se","__typename","message","count","deleteAssets","showModalAndDelete","result","modalService","dialog","title","_","translationVars","body","buttons","type","label","returnValue","y","N","ot","selectAssets","oxw","dropListDropped","previewAsset","setAsFeatured","removeAsset","assetsSetter","slice","fromComponent","size","St","concat","featuredAsset","emitChangeEvent","changeDetector","markForCheck","isFeatured","closable","locals","asset","change","emit","previousContainer","data","container","G","Dt","contentsCurrentPage$","route","queryParamMap","contentsItemsPerPage$","Q","filterTermControl","valueChanges","E","setContentsPageNumber","lt","filterChanges$","asObservable","Nt","previewUpdatedFilters","inheritFiltersChanges$","inheritFilters","collectionIdChange$","parentIdChange$","refresh$","isLoading","x","b","A","F","collection","previewCollectionVariants","parentId","filters","mapSingle","L","getCollectionContents","productVariants","M","contents$","contentsTotalItems$","ngOnChanges","next","collectionId","currentValue","updatedFilters","complete","setParam","setContentsItemsPerPage","router","navigate","relativeTo","queryParams","queryParamsHandling","replaceUrl","X","create","removeFilter","addFilter","toggleLivePreview","updateSlug","slug","description","visible","array","livePreview","localStorageService","getCollectionFilters","single$","allFilters","collectionFilters","inheritFilters$","updatedFilters$","statusChanges","filterRemoved$","S","touched","mapOperationsToInputs","arguments","parentId$","paramMap","entity$","parent","getFilterDefinition","find","code","assetsChanged","values","assetChanges","languageCode$","w","pristine","args","push","control","removeAt","markAsTouched","splice","dirty","O","getUpdatedCollection","snapshot","createCollection","markAsPristine","updateCollection","contentsComponent","canDeactivate","set","trackByFn","JSON","stringify","patchValue","isPrivate","clear","forEach","translatable","updatedFields","customFieldConfig","languageCode","defaultTranslation","assetIds","featuredAssetId","entries","dt","i","Map","children","An","hasOwnProperty","expanded","includes","rearrange$","_rearrange$","delete$","_delete$","setCollectionTree","collectionTree","resetMoveList","allMoveListItems","getMoveListItems","calculateAllMoveListItems","ancestorIdPath","has","onDrop","item","Error","index","currentIndex","onMove","onDelete","path","join","Set","j","factory","toggleExpanded","move","moveUp","moveDown","delete","depth","parentName","client","userStatus","permissions","wt","hasUpdatePermission$","hasDeletePermission$","expandAll","previousValue","split","moveListItems","collectionTreeService","drop","previousIndex","H","pipes","collections","pe","expandedIds","rearrange","deleteCollection","pt","closeContents","queryResult","getCollections","refetchOnChannelChange","items$","activeCollectionId$","activeCollectionTitle$","availableLanguages$","serverConfigService","getAvailableLanguages","contentLanguage$","uiState","contentLanguage","q","completed$","toggleExpandAll","onRearrange","moveCollection","findIndex","params","contents","setLanguage","setContentLanguage","ref","refetch","ut","updateValueCode","deleteFacetValue","addFacetValue","updateCode","customValueFields","facet","customValueFieldIsSet","getValuesFormArray","addControl","insert","getUpdatedFacet","createFacet","getAllFacets","updateFacet","getCreatedFacetValues","createFacetValues","getFacet","getUpdatedFacetValues","updateFacetValues","$","deleteFacetValues","at","Lt","Ut","Mt","Qt","controls","translations","facetId","toString","J","mt","toggleDisplayLimit","deleteFacet","getFacets","facets","po","displayLimit","initialLimit","_t","cancel","selectValues","ngAfterViewInit","setTimeout","selector","focus","resolveWith","selectedValues","gt","assign","isProductVariantMode","productVariantIds","activeChannelId","settings","getChannels","channels","currentChannel","availableChannels","selectedChannelIdControl","selectChannel","variantsPreview$","Jo","getTopVariants","priceFactorControl","price","pricePreview","selectedChannel","assignVariantsToChannel","channelId","priceFactor","channel","assignProductsToChannel","productIds","getProduct","variantList","toPromise","tt","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","ae","Yt","oe","updateProductVariants","updateProductOption","deleteProductVariant","Bo","zo","B","removeOption","Ce","provide","useExisting","R","multi","registerOnChange","onChangeFn","registerOnTouched","onTouchFn","setDisabledState","disabled","writeValue","textArea","nativeElement","locked","handleKey","key","addOptionValue","preventDefault","lastSelected","removeLastOption","input","handleBlur","isFocussed","parseInputIntoOptions","trim","decls","handleEnter","generateVariants","onFormChange","ie","getActiveChannel","currencyCode","activeChannel","addOption","variantFormValues","enabled","copyFromDefault","stopPropagation","variantsChange","ht","subscription","formArray","buildFormGroupMap","unsubscribe","getFeaturedAsset","pendingAssetChanges","optionGroupName","formGroupMap","ft","update","productOption","activeLanguage","customFieldsForm","updateVariantName","codeInputTouched","vt","getTaxRatesSimple","taxRates","taxRate$","taxCategoryIdChange$","defaultTaxZone","zone","category","grossPrice$","priceChange$","Math","round","taxCategoryId","Ct","editOption","removeFacetValue","selectFacetValueClick","removeFromChannel","assignToChannel","getGlobalSettings","globalSettings","globalTrackInventory","trackInventory","globalOutOfStockThreshold","outOfStockThreshold","add","facetValues","isDefaultChannel","ue","trackById","inventoryIsNotTracked","getTaxCategoryName","getStockOnHandMinValue","getSaleableStockLevel","useGlobalOutOfStockThreshold","stockAllocated","areAllSelected","selectedVariantIds","assetChange","variantId","toggleSelectAll","selectionChange","toggleSelectVariant","indexOf","optionName","pendingFacetValues","getFacetValueIds","existingFacetValues","facetValueIds","isVariantSelected","customOptionFields","xt","removeProductFacetValue","selectProductFacetValue","setItemsPerPage","setPage","assignVariantToChannel","removeVariantFromChannel","variantAssetChange","selectVariantFacetValue","filterInput","navigateToTab","customVariantFields","customOptionGroupFields","autoUpdateVariantNames","product$","Fo","me","Oo","filterOperator","bufferSize","refCount","variants$","Rt","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","bt","runPendingSearchIndexUpdates","deleteProduct","searchTerm","productSearchInput","setSearchTerm","selectedFacetValueIds$","getAll","setFacetValues","searchProducts","search","term","facetValueOperator","groupByProduct","result$","getPendingSearchIndexUpdates","pendingSearchIndexUpdates","setQueryParam","page","setFacetValueIds","fvids","rebuildSearchIndex","reindex","info","jobQueueService","addJob","state","Intl","NumberFormat","format","duration","indexedItemCount","time","Zt","optionGroupCustomFields","optionCustomFields","optionGroups$","getOptionGroups","getOptions","invalid","getUpdatedOptionGroup","updateProductOptionGroup","getUpdatedOption","updatedAt","setControl","At","confirm","onFormChanged","deleteVariant","Tt","initOptionsAndVariants","formValueChanged","getVariantsToAdd","generatedVariants","existing","getVariantName","isNew","getVariantPrototype","Ae","productVariantId","isDefault","optionsAreEqual","optionsAreSubset","qa","reFetchProduct","checkUniqueSkus","confirmDeletionOfObsoleteVariants","addOptionGroupsToProduct","addNewOptionsToGroups","fetchOptionGroups","createNewProductVariants","deleteObsoleteVariants","getObsoleteVariants","hasOnlyDefaultVariant","productOptionGroupId","addOptionToGroup","getProductOptionGroup","productOptionGroup","getProductVariantsOptions","toOptionString","Pt","fileSize","mimeType","width","height","source","preview","focalPoint","getAsset","yt","getCollection","Ft","Ot","It","et","Te","component","breadcrumb","resolve","Pe","ye","Fe","Oe","Ie","Le","breadcrumbKey","getName","link","Vt","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-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<div class=\"table-wrapper\">\r\n <div class=\"progress loop\" [class.visible]=\"isLoading\"></div>\r\n <vdr-data-table\r\n [class.loading]=\"isLoading\"\r\n [items]=\"contents$ | async\"\r\n [itemsPerPage]=\"contentsItemsPerPage$ | async\"\r\n [totalItems]=\"contentsTotalItems$ | async\"\r\n [currentPage]=\"contentsCurrentPage$ | async\"\r\n (pageChange)=\"setContentsPageNumber($event)\"\r\n (itemsPerPageChange)=\"setContentsItemsPerPage($event)\"\r\n >\r\n <ng-template let-variant=\"item\">\r\n <td class=\"left align-middle\">{{ variant.name }}</td>\r\n <td class=\"left align-middle\"><small class=\"sku\">{{ variant.sku }}</small></td>\r\n <td class=\"right align-middle\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['/catalog/products', variant.productId, { tab: 'variants' }]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n </ng-template>\r\n </vdr-data-table>\r\n</div>\r\n","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 {\r\n CollectionFilterParameter,\r\n ConfigurableOperationInput,\r\n DataService,\r\n GetCollectionContentsQuery,\r\n} from '@vendure/admin-ui/core';\r\nimport { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';\r\nimport {\r\n catchError,\r\n debounceTime,\r\n distinctUntilChanged,\r\n filter,\r\n finalize,\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 @Input() parentId: string;\r\n @Input() inheritFilters: boolean;\r\n @Input() updatedFilters: ConfigurableOperationInput[] | undefined;\r\n @Input() previewUpdatedFilters = false;\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 isLoading = false;\r\n private collectionIdChange$ = new BehaviorSubject<string>('');\r\n private parentIdChange$ = new BehaviorSubject<string>('');\r\n private filterChanges$ = new BehaviorSubject<ConfigurableOperationInput[]>([]);\r\n private inheritFiltersChanges$ = new BehaviorSubject<boolean>(true);\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.queryParamMap.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.queryParamMap.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 filterChanges$ = this.filterChanges$.asObservable().pipe(\r\n filter(() => this.previewUpdatedFilters),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith([]),\r\n );\r\n\r\n const inheritFiltersChanges$ = this.inheritFiltersChanges$.asObservable().pipe(\r\n filter(() => this.inheritFilters != null),\r\n distinctUntilChanged(),\r\n tap(() => this.setContentsPageNumber(1)),\r\n startWith(true),\r\n );\r\n\r\n const fetchUpdate$ = combineLatest(\r\n this.collectionIdChange$,\r\n this.parentIdChange$,\r\n this.contentsCurrentPage$,\r\n this.contentsItemsPerPage$,\r\n filterTerm$,\r\n filterChanges$,\r\n inheritFiltersChanges$,\r\n this.refresh$,\r\n );\r\n\r\n const collection$ = fetchUpdate$.pipe(\r\n takeUntil(this.destroy$),\r\n tap(() => (this.isLoading = true)),\r\n debounceTime(50),\r\n switchMap(([id, parentId, currentPage, itemsPerPage, filterTerm, filters, inheritFilters]) => {\r\n const take = itemsPerPage;\r\n const skip = (currentPage - 1) * itemsPerPage;\r\n if (filters.length && this.previewUpdatedFilters) {\r\n const filterClause = filterTerm\r\n ? ({ name: { contains: filterTerm } } as CollectionFilterParameter)\r\n : undefined;\r\n return this.dataService.collection\r\n .previewCollectionVariants(\r\n {\r\n parentId,\r\n filters,\r\n inheritFilters,\r\n },\r\n {\r\n take,\r\n skip,\r\n filter: filterClause,\r\n },\r\n )\r\n .mapSingle(data => data.previewCollectionVariants)\r\n .pipe(catchError(() => of({ items: [], totalItems: 0 })));\r\n } else if (id) {\r\n return this.dataService.collection\r\n .getCollectionContents(id, take, skip, filterTerm)\r\n .mapSingle(data => data.collection?.productVariants);\r\n } else {\r\n return of(null);\r\n }\r\n }),\r\n tap(() => (this.isLoading = false)),\r\n finalize(() => (this.isLoading = false)),\r\n );\r\n\r\n this.contents$ = collection$.pipe(map(result => (result ? result.items : [])));\r\n this.contentsTotalItems$ = collection$.pipe(map(result => (result ? result.totalItems : 0)));\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 if ('parentId' in changes) {\r\n this.parentIdChange$.next(changes.parentId.currentValue);\r\n }\r\n if ('inheritFilters' in changes) {\r\n this.inheritFiltersChanges$.next(changes.inheritFilters.currentValue);\r\n }\r\n if ('updatedFilters' in changes) {\r\n if (this.updatedFilters) {\r\n this.filterChanges$.next(this.updatedFilters);\r\n }\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(['./'], {\r\n relativeTo: this.route,\r\n queryParams: {\r\n [key]: value,\r\n },\r\n queryParamsHandling: 'merge',\r\n replaceUrl: true,\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; trackBy:trackByFn\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter(i)\"\r\n [position]=\"i\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n </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\r\n [collectionId]=\"id\"\r\n [parentId]=\"parentId$ | async\"\r\n [updatedFilters]=\"updatedFilters$ | async\"\r\n [inheritFilters]=\"inheritFilters$ | async\"\r\n [previewUpdatedFilters]=\"livePreview\"\r\n #collectionContents\r\n >\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <clr-checkbox-wrapper [class.disabled]=\"detailForm.get('filters')?.pristine\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [disabled]=\"detailForm.get('filters')?.pristine\"\r\n [ngModel]=\"livePreview\"\r\n (ngModelChange)=\"toggleLivePreview()\"\r\n />\r\n <label>{{ 'catalog.live-preview-contents' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n","import {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n OnDestroy,\r\n OnInit,\r\n ViewChild,\r\n} 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 Asset,\r\n BaseDetailComponent,\r\n Collection,\r\n CollectionFragment,\r\n ConfigurableOperation,\r\n ConfigurableOperationDefinition,\r\n ConfigurableOperationInput,\r\n CreateCollectionInput,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n encodeConfigArgValue,\r\n findTranslation,\r\n getConfigArgValue,\r\n LanguageCode,\r\n LocalStorageService,\r\n ModalService,\r\n NotificationService,\r\n Permission,\r\n ServerConfigService,\r\n unicodePatternValidator,\r\n UpdateCollectionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { combineLatest, merge, Observable, of, Subject } from 'rxjs';\r\nimport { debounceTime, distinctUntilChanged, filter, map, mergeMap, switchMap, take } from 'rxjs/operators';\r\n\r\nimport { CollectionContentsComponent } from '../collection-contents/collection-contents.component';\r\n\r\n@Component({\r\n selector: 'vdr-collection-detail',\r\n templateUrl: './collection-detail.component.html',\r\n styleUrls: ['./collection-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class CollectionDetailComponent\r\n extends BaseDetailComponent<CollectionFragment>\r\n implements OnInit, OnDestroy\r\n{\r\n customFields: CustomFieldConfig[];\r\n detailForm: FormGroup;\r\n assetChanges: { assets?: Asset[]; featuredAsset?: Asset } = {};\r\n filters: ConfigurableOperation[] = [];\r\n allFilters: ConfigurableOperationDefinition[] = [];\r\n updatedFilters$: Observable<ConfigurableOperationInput[]>;\r\n inheritFilters$: Observable<boolean>;\r\n livePreview = false;\r\n parentId$: Observable<string | undefined>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];\r\n private filterRemoved$ = new Subject<void>();\r\n @ViewChild('collectionContents') contentsComponent: CollectionContentsComponent;\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 private localStorageService: LocalStorageService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Collection');\r\n this.detailForm = this.formBuilder.group({\r\n name: ['', Validators.required],\r\n slug: ['', unicodePatternValidator(/^[\\p{Letter}0-9_-]+$/)],\r\n description: '',\r\n visible: false,\r\n inheritFilters: true,\r\n filters: this.formBuilder.array([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.livePreview = this.localStorageService.get('livePreviewCollectionContents') ?? false;\r\n }\r\n\r\n ngOnInit() {\r\n this.init();\r\n this.dataService.collection.getCollectionFilters().single$.subscribe(res => {\r\n this.allFilters = res.collectionFilters;\r\n });\r\n const filtersFormArray = this.detailForm.get('filters') as FormArray;\r\n const inheritFiltersControl = this.detailForm.get('inheritFilters') as FormControl;\r\n this.inheritFilters$ = inheritFiltersControl.valueChanges.pipe(distinctUntilChanged());\r\n this.updatedFilters$ = merge(filtersFormArray.statusChanges, this.filterRemoved$).pipe(\r\n debounceTime(200),\r\n filter(() => filtersFormArray.touched),\r\n map(() =>\r\n this.mapOperationsToInputs(this.filters, filtersFormArray.value).filter(_filter => {\r\n // ensure all the arguments have valid values. E.g. a newly-added\r\n // filter will not yet have valid values\r\n for (const arg of _filter.arguments) {\r\n if (arg.value === '') {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }),\r\n ),\r\n );\r\n this.parentId$ = this.route.paramMap.pipe(\r\n map(pm => pm.get('parentId') || undefined),\r\n switchMap(parentId => {\r\n if (parentId) {\r\n return of(parentId);\r\n } else {\r\n return this.entity$.pipe(map(collection => collection.parent?.id));\r\n }\r\n }),\r\n );\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n getFilterDefinition(_filter: ConfigurableOperation): ConfigurableOperationDefinition | undefined {\r\n return this.allFilters.find(f => f.code === _filter.code);\r\n }\r\n\r\n assetsChanged(): boolean {\r\n return !!Object.values(this.assetChanges).length;\r\n }\r\n\r\n /**\r\n * If creating a new Collection, automatically generate the slug based on the collection 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(['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 addFilter(collectionFilter: ConfigurableOperation) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n const argsHash = collectionFilter.args.reduce(\r\n (output, arg) => ({\r\n ...output,\r\n [arg.name]: getConfigArgValue(arg.value),\r\n }),\r\n {},\r\n );\r\n filtersArray.push(\r\n this.formBuilder.control({\r\n code: collectionFilter.code,\r\n args: argsHash,\r\n }),\r\n );\r\n this.filters.push({\r\n code: collectionFilter.code,\r\n args: collectionFilter.args.map(a => ({ name: a.name, value: getConfigArgValue(a.value) })),\r\n });\r\n }\r\n\r\n removeFilter(index: number) {\r\n const filtersArray = this.detailForm.get('filters') as FormArray;\r\n if (index !== -1) {\r\n filtersArray.removeAt(index);\r\n filtersArray.markAsDirty();\r\n filtersArray.markAsTouched();\r\n this.filters.splice(index, 1);\r\n this.filterRemoved$.next();\r\n }\r\n }\r\n\r\n create() {\r\n if (!this.detailForm.dirty) {\r\n return;\r\n }\r\n combineLatest(this.entity$, this.languageCode$)\r\n .pipe(\r\n take(1),\r\n mergeMap(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as CreateCollectionInput;\r\n const parentId = this.route.snapshot.paramMap.get('parentId');\r\n if (parentId) {\r\n input.parentId = parentId;\r\n }\r\n return this.dataService.collection.createCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n data => {\r\n this.notificationService.success(_('common.notify-create-success'), {\r\n entity: 'Collection',\r\n });\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.router.navigate(['../', data.createCollection.id], { relativeTo: this.route });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-create-error'), {\r\n entity: 'Collection',\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(([category, languageCode]) => {\r\n const input = this.getUpdatedCollection(\r\n category,\r\n this.detailForm,\r\n languageCode,\r\n ) as UpdateCollectionInput;\r\n return this.dataService.collection.updateCollection(input);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.assetChanges = {};\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'Collection',\r\n });\r\n this.contentsComponent.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Collection',\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 toggleLivePreview() {\r\n this.livePreview = !this.livePreview;\r\n this.localStorageService.set('livePreviewCollectionContents', this.livePreview);\r\n }\r\n\r\n trackByFn(index: number, item: ConfigurableOperation) {\r\n return JSON.stringify(item);\r\n }\r\n\r\n /**\r\n * Sets the values of the form on changes to the category or current language.\r\n */\r\n protected setFormValues(entity: CollectionFragment, languageCode: LanguageCode) {\r\n const currentTranslation = findTranslation(entity, languageCode);\r\n\r\n this.detailForm.patchValue({\r\n name: currentTranslation ? currentTranslation.name : '',\r\n slug: currentTranslation ? currentTranslation.slug : '',\r\n description: currentTranslation ? currentTranslation.description : '',\r\n visible: !entity.isPrivate,\r\n inheritFilters: entity.inheritFilters,\r\n });\r\n\r\n const formArray = this.detailForm.get('filters') as FormArray;\r\n if (formArray.length !== entity.filters.length) {\r\n formArray.clear();\r\n this.filters = [];\r\n entity.filters.forEach(f => this.addFilter(f));\r\n }\r\n\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(\r\n this.customFields,\r\n this.detailForm.get(['customFields']),\r\n entity,\r\n currentTranslation,\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Given a category and the value of the form, this method creates an updated copy of the category which\r\n * can then be persisted to the API.\r\n */\r\n private getUpdatedCollection(\r\n category: CollectionFragment,\r\n form: FormGroup,\r\n languageCode: LanguageCode,\r\n ): CreateCollectionInput | UpdateCollectionInput {\r\n const updatedCategory = createUpdatedTranslatable({\r\n translatable: category,\r\n updatedFields: form.value,\r\n customFieldConfig: this.customFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: category.name || '',\r\n slug: category.slug || '',\r\n description: category.description || '',\r\n },\r\n });\r\n return {\r\n ...updatedCategory,\r\n assetIds: this.assetChanges.assets?.map(a => a.id),\r\n featuredAssetId: this.assetChanges.featuredAsset?.id,\r\n isPrivate: !form.value.visible,\r\n filters: this.mapOperationsToInputs(this.filters, this.detailForm.value.filters),\r\n };\r\n }\r\n\r\n /**\r\n * Maps an array of conditions or actions to the input format expected by the GraphQL API.\r\n */\r\n private mapOperationsToInputs(\r\n operations: ConfigurableOperation[],\r\n formValueOperations: any,\r\n ): ConfigurableOperationInput[] {\r\n return operations.map((o, i) => {\r\n return {\r\n code: o.code,\r\n arguments: Object.entries(formValueOperations[i].args).map(([name, value], j) => {\r\n return {\r\n name,\r\n value: encodeConfigArgValue(value),\r\n };\r\n }),\r\n };\r\n });\r\n }\r\n}\r\n","export type HasParent = { id: string; parent?: { id: string } | null };\r\nexport type TreeNode<T extends HasParent> = T & { children: Array<TreeNode<T>>; expanded: boolean };\r\nexport type RootNode<T extends HasParent> = { id?: string; children: Array<TreeNode<T>> };\r\n\r\n/**\r\n * Builds a tree from an array of nodes which have a parent.\r\n * Based on https://stackoverflow.com/a/31247960/772859, modified to preserve ordering.\r\n */\r\nexport function arrayToTree<T extends HasParent>(\r\n nodes: T[],\r\n currentState?: RootNode<T>,\r\n expandedIds: string[] = [],\r\n): RootNode<T> {\r\n const topLevelNodes: Array<TreeNode<T>> = [];\r\n const mappedArr: { [id: string]: TreeNode<T> } = {};\r\n const currentStateMap = treeToMap(currentState);\r\n\r\n // First map the nodes of the array to an object -> create a hash table.\r\n for (const node of nodes) {\r\n mappedArr[node.id] = { ...(node as any), children: [] };\r\n }\r\n\r\n for (const id of nodes.map(n => n.id)) {\r\n if (mappedArr.hasOwnProperty(id)) {\r\n const mappedElem = mappedArr[id];\r\n mappedElem.expanded = currentStateMap.get(id)?.expanded ?? expandedIds.includes(id);\r\n const parent = mappedElem.parent;\r\n if (!parent) {\r\n continue;\r\n }\r\n // If the element is not at the root level, add it to its parent array of children.\r\n const parentIsRoot = !mappedArr[parent.id];\r\n if (!parentIsRoot) {\r\n if (mappedArr[parent.id]) {\r\n mappedArr[parent.id].children.push(mappedElem);\r\n } else {\r\n mappedArr[parent.id] = { children: [mappedElem] } as any;\r\n }\r\n } else {\r\n topLevelNodes.push(mappedElem);\r\n }\r\n }\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const rootId = topLevelNodes.length ? topLevelNodes[0].parent!.id : undefined;\r\n return { id: rootId, children: topLevelNodes };\r\n}\r\n\r\n/**\r\n * Converts an existing tree (as generated by the arrayToTree function) into a flat\r\n * Map. This is used to persist certain states (e.g. `expanded`) when re-building the\r\n * tree.\r\n */\r\nfunction treeToMap<T extends HasParent>(tree?: RootNode<T>): Map<string, TreeNode<T>> {\r\n const nodeMap = new Map<string, TreeNode<T>>();\r\n function visit(node: TreeNode<T>) {\r\n nodeMap.set(node.id, node);\r\n node.children.forEach(visit);\r\n }\r\n if (tree) {\r\n visit(tree as TreeNode<T>);\r\n }\r\n return nodeMap;\r\n}\r\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)=\"toggleExpanded(collection)\"\r\n >\r\n <clr-icon shape=\"folder\" *ngIf=\"!collection.expanded && !expandAll\"></clr-icon>\r\n <clr-icon shape=\"folder-open\" *ngIf=\"collection.expanded || expandAll\"></clr-icon>\r\n </button>\r\n <ng-template #folderSpacer>\r\n <div class=\"folder-button-spacer\"></div>\r\n </ng-template>\r\n {{ collection.name }}\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <vdr-chip *ngIf=\"collection.isPrivate\">{{ 'catalog.private' | translate }}</vdr-chip>\r\n <a\r\n class=\"btn btn-link btn-sm\"\r\n [routerLink]=\"['./', { contents: collection.id }]\"\r\n queryParamsHandling=\"preserve\"\r\n >\r\n <clr-icon shape=\"view-list\"></clr-icon>\r\n {{ 'catalog.view-contents' | translate }}\r\n </a>\r\n <a class=\"btn btn-link btn-sm\" [routerLink]=\"['/catalog/collections/', collection.id]\">\r\n <clr-icon shape=\"edit\"></clr-icon>\r\n {{ 'common.edit' | translate }}\r\n </a>\r\n <div class=\"drag-handle\" cdkDragHandle *vdrIfPermissions=\"['UpdateCatalog', 'UpdateCollection']\">\r\n <clr-icon shape=\"drag-handle\" size=\"24\"></clr-icon>\r\n </div>\r\n <vdr-dropdown>\r\n <button class=\"icon-button\" vdrDropdownTrigger (click)=\"getMoveListItems(collection)\">\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <a\r\n class=\"dropdown-item\"\r\n [routerLink]=\"['./', 'create', { parentId: collection.id }]\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"i === 0 || !(hasUpdatePermission$ | async)\"\r\n (click)=\"moveUp(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret up\"></clr-icon>\r\n {{ 'catalog.move-up' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n [disabled]=\"\r\n i === collectionTree.children.length - 1 || !(hasUpdatePermission$ | async)\r\n \"\r\n (click)=\"moveDown(collection, i)\"\r\n >\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n {{ 'catalog.move-down' | translate }}\r\n </button>\r\n <h4 class=\"dropdown-header\">{{ 'catalog.move-to' | translate }}</h4>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n *ngFor=\"let item of moveListItems\"\r\n (click)=\"move(collection, item.id)\"\r\n [disabled]=\"!(hasUpdatePermission$ | async)\"\r\n >\r\n <div class=\"move-to-item\">\r\n <div class=\"move-icon\">\r\n <clr-icon shape=\"child-arrow\"></clr-icon>\r\n </div>\r\n <div class=\"path\">\r\n {{ item.path }}\r\n </div>\r\n </div>\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n class=\"button\"\r\n vdrDropdownItem\r\n (click)=\"delete(collection.id)\"\r\n [disabled]=\"!(hasDeletePermission$ | async)\"\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <vdr-collection-tree-node\r\n *ngIf=\"collection.expanded || expandAll\"\r\n [expandAll]=\"expandAll\"\r\n [collectionTree]=\"collection\"\r\n [activeCollectionId]=\"activeCollectionId\"\r\n ></vdr-collection-tree-node>\r\n </div>\r\n</div>\r\n","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 { ActivatedRoute, Router } from '@angular/router';\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 private router: Router,\r\n private route: ActivatedRoute,\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 toggleExpanded(collection: TreeNode<CollectionPartial>) {\r\n collection.expanded = !collection.expanded;\r\n let expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n if (collection.expanded) {\r\n expandedIds.push(collection.id);\r\n } else {\r\n expandedIds = expandedIds.filter(id => id !== collection.id);\r\n }\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: expandedIds.filter(id => !!id).join(','),\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\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 @Input() expandedIds: string[] = [];\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, this.expandedIds);\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\" (change)=\"toggleExpandAll()\"/>\r\n <label>{{ 'catalog.expand-all-collections' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <input\r\n type='text'\r\n name='searchTerm'\r\n [formControl]='filterTermControl'\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n class='clr-input search-input ml4'\r\n />\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"collection-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateCollection']\"\r\n [routerLink]=\"['./create']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.create-new-collection' | translate }}\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<div class=\"collection-wrapper\">\r\n <vdr-collection-tree\r\n [collections]=\"items$ | async\"\r\n [activeCollectionId]=\"activeCollectionId$ | async\"\r\n [expandAll]=\"expandAll\"\r\n [expandedIds]=\"expandedIds\"\r\n (rearrange)=\"onRearrange($event)\"\r\n (deleteCollection)=\"deleteCollection($event)\"\r\n ></vdr-collection-tree>\r\n\r\n <div class=\"collection-contents\" [class.expanded]=\"activeCollectionId$ | async\">\r\n <vdr-collection-contents [collectionId]=\"activeCollectionId$ | async\">\r\n <ng-template let-count>\r\n <div class=\"collection-title\">\r\n {{ activeCollectionTitle$ | async }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <button type=\"button\" class=\"close-button\" (click)=\"closeContents()\">\r\n <clr-icon shape=\"close\"></clr-icon>\r\n </button>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n</div>\r\n","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 expandedIds: string[] = [];\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 this.expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];\r\n this.expandAll = this.route.snapshot.queryParamMap.get('expanded') === 'all';\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(term => {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n q: term || undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\r\n });\r\n\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n distinctUntilChanged(),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(() => this.refresh());\r\n this.filterTermControl.patchValue(this.route.snapshot.queryParamMap.get('q'));\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 toggleExpandAll() {\r\n this.router.navigate(['./'], {\r\n queryParams: {\r\n expanded: this.expandAll ? 'all' : undefined,\r\n },\r\n queryParamsHandling: 'merge',\r\n relativeTo: this.route,\r\n });\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 const filterTerm = this.route.snapshot.queryParamMap.get('q');\r\n this.queryResult.ref.refetch({\r\n options: {\r\n skip: 0,\r\n take: 1000,\r\n ...(filterTerm\r\n ? {\r\n filter: {\r\n name: {\r\n contains: filterTerm,\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 | undefined)?.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]=\"getStockOnHandMinValue(formGroup)\"\r\n step=\"1\"\r\n formControlName=\"stockOnHand\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"inventoryIsNotTracked(formGroup)\"\r\n />\r\n </clr-input-container>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-allocated' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-allocated-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ variant.stockAllocated }}\r\n </div>\r\n </div>\r\n <div [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\">\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.stock-saleable' | translate }}\r\n <vdr-help-tooltip\r\n [content]=\"'catalog.stock-saleable-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"value\">\r\n {{ getSaleableStockLevel(variant) }}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"variant-form-input-row\">\r\n <div\r\n class=\"out-of-stock-threshold-wrapper\"\r\n [class.inventory-untracked]=\"inventoryIsNotTracked(formGroup)\"\r\n >\r\n <label class=\"clr-control-label\"\r\n >{{ 'catalog.out-of-stock-threshold' | translate\r\n }}<vdr-help-tooltip\r\n [content]=\"'catalog.out-of-stock-threshold-tooltip' | translate\"\r\n ></vdr-help-tooltip\r\n ></label>\r\n <div class=\"flex\">\r\n <clr-input-container>\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [formControl]=\"formGroup.get('outOfStockThreshold')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n [vdrDisabled]=\"\r\n formGroup.get('useGlobalOutOfStockThreshold')?.value !==\r\n false || inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n </clr-input-container>\r\n <clr-toggle-wrapper>\r\n <input\r\n type=\"checkbox\"\r\n clrToggle\r\n name=\"useGlobalOutOfStockThreshold\"\r\n formControlName=\"useGlobalOutOfStockThreshold\"\r\n [vdrDisabled]=\"\r\n !(updatePermission | hasPermission) ||\r\n inventoryIsNotTracked(formGroup)\r\n \"\r\n />\r\n <label\r\n >{{ 'catalog.use-global-value' | translate }} ({{\r\n globalOutOfStockThreshold\r\n }})</label\r\n >\r\n </clr-toggle-wrapper>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"custom-fields\">\r\n <div class=\"variant-form-input-row\">\r\n <section formGroupName=\"customFields\" *ngIf=\"customFields.length\">\r\n <vdr-tabbed-custom-fields\r\n entityName=\"ProductVariant\"\r\n [customFields]=\"customFields\"\r\n [compact]=\"true\"\r\n [customFieldsFormGroup]=\"formGroup.get('customFields')\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-tabbed-custom-fields>\r\n </section>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\">\r\n <div class=\"options-facets\">\r\n <vdr-entity-info [entity]=\"variant\"></vdr-entity-info>\r\n <div *ngIf=\"variant.options.length\">\r\n <div class=\"options\">\r\n <vdr-chip\r\n *ngFor=\"let option of variant.options | sort: 'groupId'\"\r\n [colorFrom]=\"optionGroupName(option.groupId)\"\r\n [invert]=\"true\"\r\n (iconClick)=\"editOption(option)\"\r\n [icon]=\"(updatePermission | hasPermission) && 'pencil'\"\r\n >\r\n <span class=\"option-group-name\">{{ optionGroupName(option.groupId) }}</span>\r\n {{ optionName(option) }}\r\n </vdr-chip>\r\n <a [routerLink]=\"['./', 'options']\" class=\"btn btn-link btn-sm\"\r\n >{{ 'catalog.edit-options' | translate }}...</a\r\n >\r\n </div>\r\n </div>\r\n <div class=\"flex-spacer\"></div>\r\n <div class=\"facets\">\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of existingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <vdr-facet-value-chip\r\n *ngFor=\"let facetValue of pendingFacetValues(variant)\"\r\n [facetValue]=\"facetValue\"\r\n [removable]=\"updatePermission | hasPermission\"\r\n (remove)=\"removeFacetValue(variant, facetValue.id)\"\r\n ></vdr-facet-value-chip>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-sm btn-secondary\"\r\n (click)=\"selectFacetValueClick.emit([variant.id])\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-facets' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n <ng-container *vdrIfMultichannel>\r\n <div class=\"card-block\" *vdrIfDefaultChannelActive>\r\n <div class=\"flex channel-assignment\">\r\n <ng-container *ngFor=\"let channel of variant.channels\">\r\n <vdr-chip\r\n *ngIf=\"!isDefaultChannel(channel.code)\"\r\n icon=\"times-circle\"\r\n [title]=\"'catalog.remove-from-channel' | translate\"\r\n (iconClick)=\"\r\n removeFromChannel.emit({ channelId: channel.id, variant: variant })\r\n \"\r\n >\r\n <vdr-channel-badge [channelCode]=\"channel.code\"></vdr-channel-badge>\r\n {{ channel.code | channelCodeToLabel }}\r\n </vdr-chip>\r\n </ng-container>\r\n <button class=\"btn btn-sm\" (click)=\"assignToChannel.emit(variant)\">\r\n <clr-icon shape=\"layers\"></clr-icon>\r\n {{ 'catalog.assign-to-channel' | translate }}\r\n </button>\r\n </div>\r\n </div>\r\n </ng-container>\r\n </ng-container>\r\n </div>\r\n</div>\r\n","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 getStockOnHandMinValue(variant: FormGroup) {\r\n const effectiveOutOfStockThreshold = variant.get('useGlobalOutOfStockThreshold')?.value\r\n ? this.globalOutOfStockThreshold\r\n : variant.get('outOfStockThreshold')?.value;\r\n return effectiveOutOfStockThreshold;\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","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"></vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"></vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: {count: pendingSearchIndexUpdates}\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-checkbox-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\"/>\r\n <label>{{ 'catalog.group-by-product' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.create-new-product' | translate }}</span>\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle image-col\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n {{ groupByProduct ? result.productName : result.productVariantName }}\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n class=\"edit-button\"\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","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 ProductSearchInputComponent,\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\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 *ngIf=\"group.isNew\" class=\"btn btn-icon btn-danger-outline mt5\" (click)=\"removeOption(group)\">\r\n <clr-icon shape=\"trash\"></clr-icon>\r\n </button>\r\n </div>\r\n</div>\r\n<button\r\n class=\"btn btn-primary-outline btn-sm\"\r\n (click)=\"addOption()\"\r\n>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.create' | translate }}</th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n *ngIf=\"!variant.existing\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","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\ninterface OptionGroupUiModel {\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\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: OptionGroupUiModel[];\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 removeOption(optionGroup: OptionGroupUiModel) {\r\n this.optionGroups = this.optionGroups.filter(og => og !== optionGroup);\r\n this.generateVariants();\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 this.optionGroups = this.optionGroups.filter(g => g.values.length);\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';\r\nimport { Router } from '@angular/router';\r\nimport {\r\n BaseEntityResolver,\r\n CollectionFragment,\r\n DataService,\r\n getDefaultUiLanguage,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class CollectionResolver extends BaseEntityResolver<CollectionFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Collection' as 'Collection',\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n languageCode: getDefaultUiLanguage(),\r\n name: '',\r\n slug: '',\r\n isPrivate: false,\r\n description: '',\r\n featuredAsset: null,\r\n assets: [],\r\n translations: [],\r\n inheritFilters: true,\r\n filters: [],\r\n parent: {} as any,\r\n children: null,\r\n },\r\n id => dataService.collection.getCollection(id).mapStream(data => data.collection),\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 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 { 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 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":"504.56537eeeb3db51b7.js"}
|