@vendure/admin-ui-plugin 2.0.0-next.3 → 2.0.0-next.4
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/349.bf78d0411766ae60.js +2 -0
- package/lib/admin-ui/349.bf78d0411766ae60.js.map +1 -0
- package/lib/admin-ui/index.html +1 -1
- package/lib/admin-ui/{main.26d2935a0f6b82e8.js → main.4fea565739b4142c.js} +2 -2
- package/lib/admin-ui/{main.26d2935a0f6b82e8.js.map → main.4fea565739b4142c.js.map} +1 -1
- package/lib/admin-ui/{runtime.0a013f47235ebed5.js → runtime.fd9e61c13b055601.js} +2 -2
- package/lib/admin-ui/{runtime.0a013f47235ebed5.js.map → runtime.fd9e61c13b055601.js.map} +1 -1
- package/package.json +4 -4
- package/lib/admin-ui/349.6baced2d0430de3d.js +0 -2
- package/lib/admin-ui/349.6baced2d0430de3d.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["t","save","s","constructor","n","e","o","a","r","c","super","this","l","customFields","getCustomFieldConfig","ngOnInit","detailForm","name","tags","formBuilder","group","reduce","Object","init","ngOnDestroy","destroy","onAssetChange","get","setValue","markAsDirty","dataService","product","updateAsset","id","value","subscribe","notificationService","success","entity","error","setFormValues","length","setCustomFieldFormValues","et","selectors","N","setQueryFn","getAssetList","assets","d","h","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","D","nt","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","Y","jt","contentsCurrentPage$","route","queryParamMap","contentsItemsPerPage$","st","filterTermControl","valueChanges","$","setContentsPageNumber","filterChanges$","asObservable","previewUpdatedFilters","Vt","collectionIdChange$","parentIdChange$","refresh$","K","isLoading","x","b","collection","previewCollectionVariants","parentId","filters","mapSingle","Z","getCollectionContents","productVariants","L","contents$","contentsTotalItems$","ngOnChanges","next","collectionId","currentValue","updatedFilters","complete","setParam","setContentsItemsPerPage","router","navigate","relativeTo","queryParams","queryParamsHandling","replaceUrl","W","create","removeFilter","addFilter","toggleLivePreview","updateSlug","slug","description","visible","inheritFilters","array","livePreview","localStorageService","getCollectionFilters","single$","allFilters","collectionFilters","updatedFilters$","statusChanges","Gt","touched","mapOperationsToInputs","parentId$","paramMap","entity$","parent","getFilterDefinition","find","code","assetsChanged","values","assetChanges","languageCode$","k","pristine","args","push","control","removeAt","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","arguments","entries","lt","i","Map","children","Pn","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","G","factory","toggleExpanded","move","moveUp","moveDown","delete","depth","parentName","client","userStatus","permissions","Jt","hasUpdatePermission$","hasDeletePermission$","expandAll","previousValue","split","moveListItems","collectionTreeService","drop","previousIndex","E","pipes","collections","ue","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","S","deleteFacetValues","I","at","V","Mt","Nt","wt","Qt","controls","translations","facetId","toString","w","mt","toggleDisplayLimit","deleteFacet","getFacets","facets","mo","displayLimit","initialLimit","_t","cancel","selectValues","ngAfterViewInit","setTimeout","selector","focus","resolveWith","selectedValues","gt","assign","isProductVariantMode","productVariantIds","activeChannelId","settings","getChannels","channels","currentChannel","availableChannels","selectedChannelIdControl","selectChannel","variantsPreview$","Uo","getTopVariants","priceFactorControl","price","pricePreview","selectedChannel","assignVariantsToChannel","channelId","priceFactor","channel","assignProductsToChannel","productIds","getProduct","variantList","toPromise","X","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","re","Yt","ie","updateProductVariants","updateProductOption","deleteProductVariant","zo","Wo","j","removeOption","be","provide","useExisting","H","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","ae","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","me","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$","Io","ge","Lo","filterOperator","bufferSize","refCount","variants$","_e","productVariantMap","taxCategories$","productDetailService","activeTab$","buildVariantFormArray","facets$","getProductFormGroup","facetValues$","productChannels$","channelPriceIncludesTax$","pricesIncludeTax","location","replaceState","createUrlTree","tab","currentChannelIds","removeProductsFromChannel","variant","removeVariantsFromChannel","variantAssetsChanged","keys","variantAssetChanges","displayFacetValueModal","he","variantFacetValueChanges","variantsToCreateAreValid","createVariantsConfig","every","getUpdatedProduct","console","getUpdatedProductVariants","updateSlugAfterSave","priceWithTax","taxCategory","emitEvent","bt","selectTag","isFacetValueItem","toLowerCase","facetValue","toLocaleLowerCase","setSearchTerm","selectComponent","select","selectedItems","unselect","setFacetValues","onSelectChange","Array","isArray","lastTerm","searchTermChange","lastFacetValueIds","facetValueChange","addTagFn","isSearchHeaderSelected","itemsList","markedIndex","Zt","$t","useValue","runPendingSearchIndexUpdates","deleteProduct","searchTerm","productSearchInput","selectedFacetValueIds$","getAll","searchProducts","search","term","facetValueOperator","groupByProduct","result$","getPendingSearchIndexUpdates","pendingSearchIndexUpdates","setQueryParam","page","setFacetValueIds","fvids","rebuildSearchIndex","reindex","info","jobQueueService","addJob","state","Intl","NumberFormat","format","duration","indexedItemCount","time","Tt","optionGroupCustomFields","optionCustomFields","optionGroups$","getOptionGroups","getOptions","invalid","getUpdatedOptionGroup","updateProductOptionGroup","getUpdatedOption","updatedAt","setControl","At","confirm","onFormChanged","deleteVariant","Pt","initOptionsAndVariants","formValueChanged","getVariantsToAdd","generatedVariants","existing","getVariantName","isNew","getVariantPrototype","Pe","productVariantId","isDefault","optionsAreEqual","optionsAreSubset","Ba","reFetchProduct","checkUniqueSkus","confirmDeletionOfObsoleteVariants","addOptionGroupsToProduct","addNewOptionsToGroups","fetchOptionGroups","createNewProductVariants","deleteObsoleteVariants","getObsoleteVariants","hasOnlyDefaultVariant","productOptionGroupId","addOptionToGroup","getProductOptionGroup","productOptionGroup","getProductVariantsOptions","toOptionString","yt","fileSize","mimeType","width","height","source","preview","focalPoint","getAsset","Ft","getCollection","Ot","It","Lt","tt","ye","component","breadcrumb","resolve","Fe","Oe","Ie","Le","Me","we","breadcrumbKey","getName","link","Ut","T"],"sources":["./src/lib/catalog/src/components/asset-detail/asset-detail.component.html","./src/lib/catalog/src/components/asset-detail/asset-detail.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.ts","./src/lib/catalog/src/components/asset-list/asset-list.component.html","./src/lib/catalog/src/components/assets/assets.component.html","./src/lib/catalog/src/components/assets/assets.component.ts","./src/lib/catalog/src/components/collection-contents/collection-contents.component.html","./src/lib/catalog/src/components/collection-contents/collection-contents.component.ts","./src/lib/catalog/src/components/collection-detail/collection-detail.component.html","./src/lib/catalog/src/components/collection-detail/collection-detail.component.ts","./src/lib/catalog/src/components/collection-tree/array-to-tree.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.service.ts","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree-node.component.ts","./src/lib/catalog/src/components/collection-tree/collection-tree.component.html","./src/lib/catalog/src/components/collection-tree/collection-tree.component.ts","./src/lib/catalog/src/components/collection-list/collection-list.component.html","./src/lib/catalog/src/components/collection-list/collection-list.component.ts","./src/lib/catalog/src/components/facet-detail/facet-detail.component.html","./src/lib/catalog/src/components/facet-detail/facet-detail.component.ts","./src/lib/catalog/src/components/facet-list/facet-list.component.html","./src/lib/catalog/src/components/facet-list/facet-list.component.ts","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.html","./src/lib/catalog/src/components/apply-facet-dialog/apply-facet-dialog.component.ts","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.html","./src/lib/catalog/src/components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component.ts","./src/lib/catalog/src/providers/product-detail/replace-last.ts","./src/lib/catalog/src/providers/product-detail/product-detail.service.ts","./node_modules/@angular-devkit/build-angular/src/babel/webpack-loader.js","./src/lib/catalog/src/components/option-value-input/option-value-input.component.html","./src/lib/catalog/src/components/option-value-input/option-value-input.component.ts","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.html","./src/lib/catalog/src/components/generate-product-variants/generate-product-variants.component.ts","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.html","./src/lib/catalog/src/components/product-variants-table/product-variants-table.component.ts","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.html","./src/lib/catalog/src/components/update-product-option-dialog/update-product-option-dialog.component.ts","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.html","./src/lib/catalog/src/components/variant-price-detail/variant-price-detail.component.ts","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.html","./src/lib/catalog/src/components/product-variants-list/product-variants-list.component.ts","./src/lib/catalog/src/components/product-detail/product-detail.component.html","./src/lib/catalog/src/components/product-detail/product-detail.component.ts","./src/lib/catalog/src/components/product-search-input/product-search-input.component.html","./src/lib/catalog/src/components/product-search-input/product-search-input.component.ts","./src/lib/catalog/src/components/product-list/product-list.component.html","./src/lib/catalog/src/components/product-list/product-list.component.ts","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.html","./src/lib/catalog/src/components/product-options-editor/product-options-editor.component.ts","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.html","./src/lib/catalog/src/components/confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component.ts","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.html","./src/lib/catalog/src/components/product-variants-editor/product-variants-editor.component.ts","./src/lib/catalog/src/providers/routing/asset-resolver.ts","./src/lib/catalog/src/providers/routing/collection-resolver.ts","./src/lib/catalog/src/providers/routing/facet-resolver.ts","./src/lib/catalog/src/providers/routing/product-resolver.ts","./src/lib/catalog/src/providers/routing/product-variants-resolver.ts","./src/lib/catalog/src/catalog.routes.ts","./src/lib/catalog/src/catalog.module.ts"],"sourcesContent":["<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-entity-info [entity]=\"entity$ | async\"></vdr-entity-info>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-detail\"></vdr-action-bar-items>\r\n <button\r\n *vdrIfPermissions=\"['UpdateCatalog', 'UpdateAsset']\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.invalid || detailForm.pristine\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<vdr-asset-preview\r\n [asset]=\"entity$ | async\"\r\n [editable]=\"true\"\r\n [customFields]=\"customFields\"\r\n [customFieldsForm]=\"detailForm.get('customFields')\"\r\n (assetChange)=\"onAssetChange($event)\"\r\n></vdr-asset-preview>\r\n","import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';\r\nimport { FormBuilder, FormControl, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseDetailComponent,\r\n CustomFieldConfig,\r\n DataService,\r\n GetAssetQuery,\r\n LanguageCode,\r\n NotificationService,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-asset-detail',\r\n templateUrl: './asset-detail.component.html',\r\n styleUrls: ['./asset-detail.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetDetailComponent\r\n extends BaseDetailComponent<NonNullable<GetAssetQuery['asset']>>\r\n implements OnInit, OnDestroy\r\n{\r\n detailForm = new FormGroup({});\r\n customFields: CustomFieldConfig[];\r\n\r\n constructor(\r\n router: Router,\r\n route: ActivatedRoute,\r\n serverConfigService: ServerConfigService,\r\n private notificationService: NotificationService,\r\n protected dataService: DataService,\r\n private formBuilder: FormBuilder,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.customFields = this.getCustomFieldConfig('Asset');\r\n }\r\n\r\n ngOnInit() {\r\n this.detailForm = new FormGroup({\r\n name: new FormControl(''),\r\n tags: new FormControl([]),\r\n customFields: this.formBuilder.group(\r\n this.customFields.reduce((hash, field) => ({ ...hash, [field.name]: '' }), {}),\r\n ),\r\n });\r\n this.init();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.destroy();\r\n }\r\n\r\n onAssetChange(event: { id: string; name: string; tags: string[] }) {\r\n this.detailForm.get('name')?.setValue(event.name);\r\n this.detailForm.get('tags')?.setValue(event.tags);\r\n this.detailForm.markAsDirty();\r\n }\r\n\r\n save() {\r\n this.dataService.product\r\n .updateAsset({\r\n id: this.id,\r\n name: this.detailForm.value.name,\r\n tags: this.detailForm.value.tags,\r\n customFields: this.detailForm.value.customFields,\r\n })\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-update-success'), { entity: 'Asset' });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'Asset',\r\n });\r\n },\r\n );\r\n }\r\n\r\n protected setFormValues(entity: NonNullable<GetAssetQuery['asset']>, languageCode: LanguageCode): void {\r\n this.detailForm.get('name')?.setValue(entity.name);\r\n this.detailForm.get('tags')?.setValue(entity.tags);\r\n if (this.customFields.length) {\r\n this.setCustomFieldFormValues(this.customFields, this.detailForm.get(['customFields']), entity);\r\n }\r\n }\r\n}\r\n","import { Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n Asset,\r\n BaseListComponent,\r\n DataService,\r\n DeletionResult,\r\n GetAssetListQuery,\r\n GetAssetListQueryVariables,\r\n ItemOf,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SortOrder,\r\n TagFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { PaginationInstance } from 'ngx-pagination';\r\nimport { BehaviorSubject, combineLatest, EMPTY, Observable } from 'rxjs';\r\nimport { debounceTime, finalize, map, switchMap, takeUntil } from 'rxjs/operators';\r\n\r\n@Component({\r\n selector: 'vdr-asset-list',\r\n templateUrl: './asset-list.component.html',\r\n styleUrls: ['./asset-list.component.scss'],\r\n})\r\nexport class AssetListComponent\r\n extends BaseListComponent<\r\n GetAssetListQuery,\r\n ItemOf<GetAssetListQuery, 'assets'>,\r\n GetAssetListQueryVariables\r\n >\r\n implements OnInit\r\n{\r\n searchTerm$ = new BehaviorSubject<string | undefined>(undefined);\r\n filterByTags$ = new BehaviorSubject<TagFragment[] | undefined>(undefined);\r\n uploading = false;\r\n allTags$: Observable<TagFragment[]>;\r\n paginationConfig$: Observable<PaginationInstance>;\r\n\r\n constructor(\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n private dataService: DataService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n super.setQueryFn(\r\n (...args: any[]) => this.dataService.product.getAssetList(...args),\r\n data => data.assets,\r\n (skip, take) => {\r\n const searchTerm = this.searchTerm$.value;\r\n const tags = this.filterByTags$.value?.map(t => t.value);\r\n return {\r\n options: {\r\n skip,\r\n take,\r\n ...(searchTerm\r\n ? {\r\n filter: {\r\n name: { contains: searchTerm },\r\n },\r\n }\r\n : {}),\r\n sort: {\r\n createdAt: SortOrder.DESC,\r\n },\r\n tags,\r\n tagsOperator: LogicalOperator.AND,\r\n },\r\n };\r\n },\r\n { take: 25, skip: 0 },\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n this.paginationConfig$ = combineLatest(this.itemsPerPage$, this.currentPage$, this.totalItems$).pipe(\r\n map(([itemsPerPage, currentPage, totalItems]) => ({ itemsPerPage, currentPage, totalItems })),\r\n );\r\n this.searchTerm$.pipe(debounceTime(250), takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n\r\n this.filterByTags$.pipe(takeUntil(this.destroy$)).subscribe(() => this.refresh());\r\n this.allTags$ = this.dataService.product.getTagList().mapStream(data => data.tags.items);\r\n }\r\n\r\n filesSelected(files: File[]) {\r\n if (files.length) {\r\n this.uploading = true;\r\n this.dataService.product\r\n .createAssets(files)\r\n .pipe(finalize(() => (this.uploading = false)))\r\n .subscribe(({ createAssets }) => {\r\n let successCount = 0;\r\n for (const result of createAssets) {\r\n switch (result.__typename) {\r\n case 'Asset':\r\n successCount++;\r\n break;\r\n case 'MimeTypeError':\r\n this.notificationService.error(result.message);\r\n break;\r\n }\r\n }\r\n if (0 < successCount) {\r\n super.refresh();\r\n this.notificationService.success(_('asset.notify-create-assets-success'), {\r\n count: successCount,\r\n });\r\n }\r\n });\r\n }\r\n }\r\n\r\n deleteAssets(assets: Asset[]) {\r\n this.showModalAndDelete(assets.map(a => a.id))\r\n .pipe(\r\n switchMap(response => {\r\n if (response.result === DeletionResult.DELETED) {\r\n return [true];\r\n } else {\r\n return this.showModalAndDelete(\r\n assets.map(a => a.id),\r\n response.message || '',\r\n ).pipe(map(r => r.result === DeletionResult.DELETED));\r\n }\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Assets',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Assets',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private showModalAndDelete(assetIds: string[], message?: string) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-assets'),\r\n translationVars: {\r\n count: assetIds.length,\r\n },\r\n body: message,\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(res => (res ? this.dataService.product.deleteAssets(assetIds, !!message) : EMPTY)),\r\n map(res => res.deleteAssets),\r\n );\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <vdr-asset-search-input\r\n class=\"pr4 mt1\"\r\n [tags]=\"allTags$ | async\"\r\n (searchTermChange)=\"searchTerm$.next($event)\"\r\n (tagsChange)=\"filterByTags$.next($event)\"\r\n ></vdr-asset-search-input>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"asset-list\"></vdr-action-bar-items>\r\n <vdr-asset-file-input\r\n (selectFiles)=\"filesSelected($event)\"\r\n [uploading]=\"uploading\"\r\n dropZoneTarget=\".content-area\"\r\n ></vdr-asset-file-input>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-asset-gallery\r\n [assets]=\"(items$ | async)! | paginate: (paginationConfig$ | async) || {}\"\r\n [multiSelect]=\"true\"\r\n [canDelete]=\"['DeleteCatalog', 'DeleteAsset'] | hasPermission\"\r\n (deleteAssets)=\"deleteAssets($event)\"\r\n></vdr-asset-gallery>\r\n\r\n<div class=\"paging-controls\">\r\n <vdr-items-per-page-controls\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n ></vdr-items-per-page-controls>\r\n\r\n <vdr-pagination-controls\r\n [currentPage]=\"currentPage$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n ></vdr-pagination-controls>\r\n</div>\r\n","<div class=\"card\" *ngIf=\"!compact; else compactView\">\r\n <div class=\"card-img\">\r\n <div class=\"featured-asset\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'small'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"image\" size=\"128\"></clr-icon>\r\n <div>{{ 'catalog.no-featured-asset' | translate }}</div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"card-block\"><ng-container *ngTemplateOutlet=\"assetList\"></ng-container></div>\r\n <div class=\"card-footer\" *vdrIfPermissions=\"updatePermissions\">\r\n <button class=\"btn\" (click)=\"selectAssets()\">\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n </div>\r\n</div>\r\n\r\n<ng-template #compactView>\r\n <div class=\"featured-asset compact\">\r\n <img\r\n *ngIf=\"featuredAsset\"\r\n [src]=\"featuredAsset | assetPreview:'thumb'\"\r\n (click)=\"previewAsset(featuredAsset)\"\r\n />\r\n\r\n <div class=\"placeholder\" *ngIf=\"!featuredAsset\" (click)=\"selectAssets()\"><clr-icon shape=\"image\" size=\"150\"></clr-icon></div>\r\n </div>\r\n <ng-container *ngTemplateOutlet=\"assetList\"></ng-container>\r\n <button\r\n *vdrIfPermissions=\"updatePermissions\"\r\n class=\"compact-select btn btn-icon btn-sm btn-block\"\r\n [title]=\"'asset.add-asset' | translate\"\r\n (click)=\"selectAssets()\"\r\n >\r\n <clr-icon shape=\"attachment\"></clr-icon>\r\n {{ 'asset.add-asset' | translate }}\r\n </button>\r\n</ng-template>\r\n\r\n<ng-template #assetList>\r\n <div class=\"all-assets\" [class.compact]=\"compact\" cdkDropListGroup>\r\n <div\r\n *ngFor=\"let asset of assets; let index = index\"\r\n class=\"drop-list\"\r\n cdkDropList\r\n cdkDropListOrientation=\"horizontal\"\r\n [cdkDropListData]=\"index\"\r\n [cdkDropListDisabled]=\"!(updatePermissions | hasPermission)\"\r\n (cdkDropListDropped)=\"dropListDropped($event)\"\r\n >\r\n <vdr-dropdown cdkDrag>\r\n <div\r\n class=\"asset-thumb\"\r\n vdrDropdownTrigger\r\n [class.featured]=\"isFeatured(asset)\"\r\n [title]=\"\"\r\n tabindex=\"0\"\r\n >\r\n <img [src]=\"asset | assetPreview:'tiny'\" />\r\n </div>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button type=\"button\" vdrDropdownItem (click)=\"previewAsset(asset)\">\r\n {{ 'asset.preview' | translate }}\r\n </button>\r\n <button\r\n type=\"button\"\r\n [disabled]=\"isFeatured(asset) || !(updatePermissions | hasPermission)\"\r\n vdrDropdownItem\r\n (click)=\"setAsFeatured(asset)\"\r\n >\r\n {{ 'asset.set-as-featured-asset' | translate }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n <button\r\n type=\"button\"\r\n class=\"remove-asset\"\r\n vdrDropdownItem\r\n [disabled]=\"!(updatePermissions | hasPermission)\"\r\n (click)=\"removeAsset(asset)\"\r\n >\r\n {{ 'asset.remove-asset' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n</ng-template>\r\n","import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';\r\nimport {\r\n ChangeDetectionStrategy,\r\n ChangeDetectorRef,\r\n Component,\r\n EventEmitter,\r\n HostBinding,\r\n Input,\r\n Output,\r\n} from '@angular/core';\r\nimport {\r\n Asset,\r\n AssetPickerDialogComponent,\r\n AssetPreviewDialogComponent,\r\n ModalService,\r\n Permission,\r\n} from '@vendure/admin-ui/core';\r\nimport { unique } from '@vendure/common/lib/unique';\r\n\r\nexport interface AssetChange {\r\n assets: Asset[];\r\n featuredAsset: Asset | undefined;\r\n}\r\n\r\n/**\r\n * A component which displays the Assets, and allows assets to be removed and\r\n * added, and for the featured asset to be set.\r\n *\r\n * Note: rather complex code for drag drop is due to a limitation of the default CDK implementation\r\n * which is addressed by a work-around from here: https://github.com/angular/components/issues/13372#issuecomment-483998378\r\n */\r\n@Component({\r\n selector: 'vdr-assets',\r\n templateUrl: './assets.component.html',\r\n styleUrls: ['./assets.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class AssetsComponent {\r\n @Input('assets') set assetsSetter(val: Asset[]) {\r\n // create a new non-readonly array of assets\r\n this.assets = (val || []).slice();\r\n }\r\n\r\n @Input() featuredAsset: Asset | undefined;\r\n @HostBinding('class.compact')\r\n @Input()\r\n compact = false;\r\n @Output() change = new EventEmitter<AssetChange>();\r\n\r\n public assets: Asset[] = [];\r\n\r\n @Input()\r\n updatePermissions: string | string[] | Permission | Permission[];\r\n\r\n constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}\r\n\r\n selectAssets() {\r\n this.modalService\r\n .fromComponent(AssetPickerDialogComponent, {\r\n size: 'xl',\r\n })\r\n .subscribe(result => {\r\n if (result && result.length) {\r\n this.assets = unique(this.assets.concat(result), 'id');\r\n if (!this.featuredAsset) {\r\n this.featuredAsset = result[0];\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n this.changeDetector.markForCheck();\r\n }\r\n });\r\n }\r\n\r\n setAsFeatured(asset: Asset) {\r\n this.featuredAsset = asset;\r\n this.emitChangeEvent(this.assets, asset);\r\n }\r\n\r\n isFeatured(asset: Asset): boolean {\r\n return !!this.featuredAsset && this.featuredAsset.id === asset.id;\r\n }\r\n\r\n previewAsset(asset: Asset) {\r\n this.modalService\r\n .fromComponent(AssetPreviewDialogComponent, {\r\n size: 'xl',\r\n closable: true,\r\n locals: { asset },\r\n })\r\n .subscribe();\r\n }\r\n\r\n removeAsset(asset: Asset) {\r\n this.assets = this.assets.filter(a => a.id !== asset.id);\r\n if (this.featuredAsset && this.featuredAsset.id === asset.id) {\r\n this.featuredAsset = this.assets.length > 0 ? this.assets[0] : undefined;\r\n }\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n\r\n private emitChangeEvent(assets: Asset[], featuredAsset: Asset | undefined) {\r\n this.change.emit({\r\n assets,\r\n featuredAsset,\r\n });\r\n }\r\n\r\n dropListDropped(event: CdkDragDrop<number>) {\r\n moveItemInArray(this.assets, event.previousContainer.data, event.container.data);\r\n this.emitChangeEvent(this.assets, this.featuredAsset);\r\n }\r\n}\r\n","<div class=\"contents-header\">\r\n <div class=\"header-title-row\">\r\n <ng-container\r\n *ngTemplateOutlet=\"headerTemplate; context: { $implicit: contentsTotalItems$ | async }\"\r\n ></ng-container>\r\n </div>\r\n <input\r\n type=\"text\"\r\n [placeholder]=\"'catalog.filter-by-name' | translate\"\r\n [formControl]=\"filterTermControl\"\r\n />\r\n</div>\r\n<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() 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 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 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 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]) => {\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 },\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 ('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\">\r\n <vdr-configurable-input\r\n (remove)=\"removeFilter($event)\"\r\n [operation]=\"filter\"\r\n [operationDefinition]=\"getFilterDefinition(filter)\"\r\n [formControlName]=\"i\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n ></vdr-configurable-input>\r\n </ng-container>\r\n </div>\r\n\r\n <div *vdrIfPermissions=\"updatePermission\">\r\n <vdr-dropdown>\r\n <button class=\"btn btn-outline\" vdrDropdownTrigger>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'marketing.add-condition' | translate }}\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-left\">\r\n <button\r\n *ngFor=\"let filter of allFilters\"\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"addFilter(filter)\"\r\n >\r\n {{ filter.description }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n </div>\r\n <div class=\"clr-col\">\r\n <vdr-collection-contents\r\n [collectionId]=\"id\"\r\n [parentId]=\"parentId$ | async\"\r\n [updatedFilters]=\"updatedFilters$ | async\"\r\n [previewUpdatedFilters]=\"livePreview\"\r\n #collectionContents\r\n >\r\n <ng-template let-count>\r\n <div class=\"contents-title\">\r\n {{ 'catalog.collection-contents' | translate }} ({{\r\n 'common.results-count' | translate: { count: count }\r\n }})\r\n </div>\r\n <clr-checkbox-wrapper [class.disabled]=\"detailForm.get('filters')?.pristine\">\r\n <input\r\n type=\"checkbox\"\r\n clrCheckbox\r\n [ngModelOptions]=\"{ standalone: true }\"\r\n [disabled]=\"detailForm.get('filters')?.pristine\"\r\n [ngModel]=\"livePreview\"\r\n (ngModelChange)=\"toggleLivePreview()\"\r\n />\r\n <label>{{ 'catalog.live-preview-contents' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </ng-template>\r\n </vdr-collection-contents>\r\n </div>\r\n </div>\r\n</form>\r\n","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, 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, Observable, of } from 'rxjs';\r\nimport { debounceTime, 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 livePreview = false;\r\n parentId$: Observable<string | undefined>;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateCollection];\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 this.updatedFilters$ = filtersFormArray.statusChanges.pipe(\r\n debounceTime(200),\r\n filter(() => filtersFormArray.touched),\r\n map(status => this.mapOperationsToInputs(this.filters, filtersFormArray.value)),\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 this.filters.splice(index, 1);\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","<ng-select\r\n [addTag]=\"addTagFn\"\r\n [placeholder]=\"'catalog.search-product-name-or-code' | translate\"\r\n [items]=\"facetValueResults\"\r\n [searchFn]=\"filterFacetResults\"\r\n [hideSelected]=\"true\"\r\n [multiple]=\"true\"\r\n [markFirst]=\"false\"\r\n (change)=\"onSelectChange($event)\"\r\n #selectComponent\r\n>\r\n <ng-template ng-header-tmp>\r\n <div\r\n class=\"search-header\"\r\n *ngIf=\"selectComponent.searchTerm\"\r\n [class.selected]=\"isSearchHeaderSelected()\"\r\n (click)=\"selectComponent.selectTag()\"\r\n >\r\n {{ 'catalog.search-for-term' | translate }}: {{ selectComponent.searchTerm }}\r\n </div>\r\n </ng-template>\r\n <ng-template ng-label-tmp let-item=\"item\" let-clear=\"clear\">\r\n <ng-container *ngIf=\"item.facetValue\">\r\n <vdr-facet-value-chip\r\n [facetValue]=\"item.facetValue\"\r\n [removable]=\"true\"\r\n (remove)=\"clear(item)\"\r\n ></vdr-facet-value-chip>\r\n </ng-container>\r\n <ng-container *ngIf=\"!item.facetValue\">\r\n <vdr-chip [icon]=\"'times'\" (iconClick)=\"clear(item)\">\"{{ item.label }}\"</vdr-chip>\r\n </ng-container>\r\n </ng-template>\r\n <ng-template ng-option-tmp let-item=\"item\" let-index=\"index\" let-search=\"searchTerm\">\r\n <ng-container *ngIf=\"item.facetValue\">\r\n <vdr-facet-value-chip [facetValue]=\"item.facetValue\" [removable]=\"false\"></vdr-facet-value-chip>\r\n </ng-container>\r\n </ng-template>\r\n</ng-select>\r\n","import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';\r\nimport { NgSelectComponent, SELECTION_MODEL_FACTORY } from '@ng-select/ng-select';\r\nimport { SearchProductsQuery, SingleSearchSelectionModelFactory } from '@vendure/admin-ui/core';\r\nimport { notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\n\r\ntype FacetValueResult = SearchProductsQuery['search']['facetValues'][number];\r\n\r\n@Component({\r\n selector: 'vdr-product-search-input',\r\n templateUrl: './product-search-input.component.html',\r\n styleUrls: ['./product-search-input.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n providers: [{ provide: SELECTION_MODEL_FACTORY, useValue: SingleSearchSelectionModelFactory }],\r\n})\r\nexport class ProductSearchInputComponent {\r\n @Input() facetValueResults: FacetValueResult;\r\n @Output() searchTermChange = new EventEmitter<string>();\r\n @Output() facetValueChange = new EventEmitter<string[]>();\r\n @ViewChild('selectComponent', { static: true }) private selectComponent: NgSelectComponent;\r\n private lastTerm = '';\r\n private lastFacetValueIds: string[] = [];\r\n\r\n setSearchTerm(term: string | null) {\r\n if (term) {\r\n this.selectComponent.select({ label: term, value: { label: term } });\r\n } else {\r\n const currentTerm = this.selectComponent.selectedItems.find(i => !this.isFacetValueItem(i.value));\r\n if (currentTerm) {\r\n this.selectComponent.unselect(currentTerm);\r\n }\r\n }\r\n }\r\n\r\n setFacetValues(ids: string[]) {\r\n const items = this.selectComponent.items;\r\n\r\n this.selectComponent.selectedItems.forEach(item => {\r\n if (this.isFacetValueItem(item.value) && !ids.includes(item.value.facetValue.id)) {\r\n this.selectComponent.unselect(item);\r\n }\r\n });\r\n\r\n ids.map(id => {\r\n return items?.find(item => this.isFacetValueItem(item) && item.facetValue.id === id);\r\n })\r\n .filter(notNullOrUndefined)\r\n .forEach(item => {\r\n const isSelected = this.selectComponent.selectedItems.find(i => {\r\n const val = i.value;\r\n if (this.isFacetValueItem(val)) {\r\n return val.facetValue.id === item.facetValue.id;\r\n }\r\n return false;\r\n });\r\n if (!isSelected) {\r\n this.selectComponent.select({ label: '', value: item });\r\n }\r\n });\r\n }\r\n\r\n filterFacetResults = (term: string, item: FacetValueResult | { label: string }) => {\r\n if (!this.isFacetValueItem(item)) {\r\n return false;\r\n }\r\n\r\n const cix = term.indexOf(':');\r\n const facetName = cix > -1 ? term.toLowerCase().slice(0, cix) : null;\r\n const facetVal = cix > -1 ? term.toLowerCase().slice(cix + 1) : term.toLowerCase();\r\n\r\n if (facetName) {\r\n return (\r\n item.facetValue.facet.name.toLowerCase().includes(facetName) &&\r\n item.facetValue.name.toLocaleLowerCase().includes(facetVal)\r\n );\r\n }\r\n\r\n return (\r\n item.facetValue.name.toLowerCase().includes(term.toLowerCase()) ||\r\n item.facetValue.facet.name.toLowerCase().includes(term.toLowerCase())\r\n );\r\n };\r\n\r\n onSelectChange(selectedItems: Array<FacetValueResult | { label: string }>) {\r\n if (!Array.isArray(selectedItems)) {\r\n selectedItems = [selectedItems];\r\n }\r\n const searchTermItem = selectedItems.find(item => !this.isFacetValueItem(item)) as\r\n | { label: string }\r\n | undefined;\r\n const searchTerm = searchTermItem ? searchTermItem.label : '';\r\n\r\n const facetValueIds = selectedItems.filter(this.isFacetValueItem).map(i => i.facetValue.id);\r\n\r\n if (searchTerm !== this.lastTerm) {\r\n this.searchTermChange.emit(searchTerm);\r\n this.lastTerm = searchTerm;\r\n }\r\n if (this.lastFacetValueIds.join(',') !== facetValueIds.join(',')) {\r\n this.facetValueChange.emit(facetValueIds);\r\n this.lastFacetValueIds = facetValueIds;\r\n }\r\n }\r\n\r\n addTagFn(item: any) {\r\n return { label: item };\r\n }\r\n\r\n isSearchHeaderSelected(): boolean {\r\n return this.selectComponent.itemsList.markedIndex === -1;\r\n }\r\n\r\n private isFacetValueItem = (input: unknown): input is FacetValueResult => {\r\n return typeof input === 'object' && !!input && input.hasOwnProperty('facetValue');\r\n };\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left [grow]=\"true\">\r\n <div class=\"search-form\">\r\n <vdr-product-search-input\r\n #productSearchInputComponent\r\n [facetValueResults]=\"facetValues$ | async\"\r\n (searchTermChange)=\"setSearchTerm($event)\"\r\n (facetValueChange)=\"setFacetValueIds($event)\"\r\n ></vdr-product-search-input>\r\n <vdr-dropdown class=\"search-settings-menu mr3\">\r\n <button\r\n type=\"button\"\r\n class=\"icon-button search-index-button\"\r\n [title]=\"\r\n (pendingSearchIndexUpdates\r\n ? 'catalog.pending-search-index-updates'\r\n : 'catalog.search-index-controls'\r\n ) | translate\r\n \"\r\n vdrDropdownTrigger\r\n >\r\n <clr-icon shape=\"cog\"></clr-icon>\r\n <vdr-status-badge *ngIf=\"pendingSearchIndexUpdates\" type=\"warning\"> </vdr-status-badge>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <h4 class=\"dropdown-header\">{{ 'catalog.search-index-controls' | translate }}</h4>\r\n <ng-container *ngIf=\"pendingSearchIndexUpdates\">\r\n <button\r\n type=\"button\"\r\n class=\"run-updates-button\"\r\n vdrDropdownItem\r\n (click)=\"runPendingSearchIndexUpdates()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n <vdr-status-badge type=\"warning\"> </vdr-status-badge>\r\n {{\r\n 'catalog.run-pending-search-index-updates'\r\n | translate: { count: pendingSearchIndexUpdates }\r\n }}\r\n </button>\r\n <div class=\"dropdown-divider\"></div>\r\n </ng-container>\r\n <button\r\n type=\"button\"\r\n vdrDropdownItem\r\n (click)=\"rebuildSearchIndex()\"\r\n [disabled]=\"!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)\"\r\n >\r\n {{ 'catalog.rebuild-search-index' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </div>\r\n <div class=\"flex wrap\">\r\n <clr-checkbox-wrapper class=\"mt2\">\r\n <input type=\"checkbox\" clrCheckbox [(ngModel)]=\"groupByProduct\" (ngModelChange)=\"refresh()\" />\r\n <label>{{ 'catalog.group-by-product' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"contentLanguage$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </div>\r\n </vdr-ab-left>\r\n <vdr-ab-right>\r\n <vdr-action-bar-items locationId=\"product-list\"></vdr-action-bar-items>\r\n <a\r\n class=\"btn btn-primary\"\r\n [routerLink]=\"['./create']\"\r\n *vdrIfPermissions=\"['CreateCatalog', 'CreateProduct']\"\r\n >\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n <span class=\"full-label\">{{ 'catalog.create-new-product' | translate }}</span>\r\n </a>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<vdr-data-table\r\n [items]=\"items$ | async\"\r\n [itemsPerPage]=\"itemsPerPage$ | async\"\r\n [totalItems]=\"totalItems$ | async\"\r\n [currentPage]=\"currentPage$ | async\"\r\n (pageChange)=\"setPageNumber($event)\"\r\n (itemsPerPageChange)=\"setItemsPerPage($event)\"\r\n>\r\n <ng-template let-result=\"item\">\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n <div class=\"image-placeholder\">\r\n <img\r\n *ngIf=\"\r\n groupByProduct\r\n ? result.productAsset\r\n : result.productVariantAsset || result.productAsset as asset;\r\n else imagePlaceholder\r\n \"\r\n [src]=\"asset | assetPreview: 'tiny'\"\r\n />\r\n <ng-template #imagePlaceholder>\r\n <div class=\"placeholder\">\r\n <clr-icon shape=\"image\" size=\"48\"></clr-icon>\r\n </div>\r\n </ng-template>\r\n </div>\r\n </td>\r\n <td class=\"left align-middle\" [class.disabled]=\"!result.enabled\">\r\n {{ groupByProduct ? result.productName : result.productVariantName }}\r\n </td>\r\n <td class=\"align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-chip *ngIf=\"!result.enabled\">{{ 'common.disabled' | translate }}</vdr-chip>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-table-row-action\r\n iconShape=\"edit\"\r\n [label]=\"'common.edit' | translate\"\r\n [linkTo]=\"['./', result.productId]\"\r\n ></vdr-table-row-action>\r\n </td>\r\n <td class=\"right align-middle\" [class.disabled]=\"!result.enabled\">\r\n <vdr-dropdown>\r\n <button type=\"button\" class=\"btn btn-link btn-sm\" vdrDropdownTrigger>\r\n {{ 'common.actions' | translate }}\r\n <clr-icon shape=\"caret down\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteProduct(result.productId)\"\r\n [disabled]=\"!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </ng-template>\r\n</vdr-data-table>\r\n","import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseListComponent,\r\n DataService,\r\n ItemOf,\r\n JobQueueService,\r\n JobState,\r\n LanguageCode,\r\n LogicalOperator,\r\n ModalService,\r\n NotificationService,\r\n SearchInput,\r\n SearchProductsQuery,\r\n SearchProductsQueryVariables,\r\n ServerConfigService,\r\n} from '@vendure/admin-ui/core';\r\nimport { EMPTY, Observable } from 'rxjs';\r\nimport { delay, map, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';\r\n\r\nimport { ProductSearchInputComponent } from '../product-search-input/product-search-input.component';\r\n\r\n@Component({\r\n selector: 'vdr-products-list',\r\n templateUrl: './product-list.component.html',\r\n styleUrls: ['./product-list.component.scss'],\r\n})\r\nexport class ProductListComponent\r\n extends BaseListComponent<\r\n SearchProductsQuery,\r\n ItemOf<SearchProductsQuery, 'search'>,\r\n SearchProductsQueryVariables\r\n >\r\n implements OnInit, AfterViewInit\r\n{\r\n searchTerm = '';\r\n facetValueIds: string[] = [];\r\n groupByProduct = true;\r\n selectedFacetValueIds$: Observable<string[]>;\r\n facetValues$: Observable<SearchProductsQuery['search']['facetValues']>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n contentLanguage$: Observable<LanguageCode>;\r\n pendingSearchIndexUpdates = 0;\r\n\r\n @ViewChild('productSearchInputComponent', { static: true })\r\n private productSearchInput: ProductSearchInputComponent;\r\n constructor(\r\n private dataService: DataService,\r\n private modalService: ModalService,\r\n private notificationService: NotificationService,\r\n private jobQueueService: JobQueueService,\r\n private serverConfigService: ServerConfigService,\r\n router: Router,\r\n route: ActivatedRoute,\r\n ) {\r\n super(router, route);\r\n this.route.queryParamMap\r\n .pipe(\r\n map(qpm => qpm.get('q')),\r\n takeUntil(this.destroy$),\r\n )\r\n .subscribe(term => {\r\n this.searchTerm = term || '';\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setSearchTerm(term);\r\n }\r\n });\r\n this.selectedFacetValueIds$ = this.route.queryParamMap.pipe(map(qpm => qpm.getAll('fvids')));\r\n\r\n this.selectedFacetValueIds$.pipe(takeUntil(this.destroy$)).subscribe(ids => {\r\n this.facetValueIds = ids;\r\n if (this.productSearchInput) {\r\n this.productSearchInput.setFacetValues(ids);\r\n }\r\n });\r\n super.setQueryFn(\r\n (...args: any[]) =>\r\n this.dataService.product.searchProducts(this.searchTerm, ...args).refetchOnChannelChange(),\r\n data => data.search,\r\n // tslint:disable-next-line:no-shadowed-variable\r\n (skip, take) => ({\r\n input: {\r\n skip,\r\n take,\r\n term: this.searchTerm,\r\n facetValueIds: this.facetValueIds,\r\n facetValueOperator: LogicalOperator.AND,\r\n groupByProduct: this.groupByProduct,\r\n } as SearchInput,\r\n }),\r\n );\r\n }\r\n\r\n ngOnInit() {\r\n super.ngOnInit();\r\n\r\n this.facetValues$ = this.result$.pipe(map(data => data.search.facetValues));\r\n\r\n this.facetValues$\r\n .pipe(take(1), delay(100), withLatestFrom(this.selectedFacetValueIds$))\r\n .subscribe(([__, ids]) => {\r\n this.productSearchInput.setFacetValues(ids);\r\n });\r\n this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();\r\n this.contentLanguage$ = this.dataService.client\r\n .uiState()\r\n .mapStream(({ uiState }) => uiState.contentLanguage)\r\n .pipe(tap(() => this.refresh()));\r\n\r\n this.dataService.product\r\n .getPendingSearchIndexUpdates()\r\n .mapSingle(({ pendingSearchIndexUpdates }) => pendingSearchIndexUpdates)\r\n .subscribe(value => (this.pendingSearchIndexUpdates = value));\r\n }\r\n\r\n ngAfterViewInit() {\r\n if (this.productSearchInput && this.searchTerm) {\r\n setTimeout(() => this.productSearchInput.setSearchTerm(this.searchTerm));\r\n }\r\n }\r\n\r\n setSearchTerm(term: string) {\r\n this.searchTerm = term;\r\n this.setQueryParam({ q: term || null, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n setFacetValueIds(ids: string[]) {\r\n this.facetValueIds = ids;\r\n this.setQueryParam({ fvids: ids, page: 1 });\r\n this.refresh();\r\n }\r\n\r\n rebuildSearchIndex() {\r\n this.dataService.product.reindex().subscribe(({ reindex }) => {\r\n this.notificationService.info(_('catalog.reindexing'));\r\n this.jobQueueService.addJob(reindex.id, job => {\r\n if (job.state === JobState.COMPLETED) {\r\n const time = new Intl.NumberFormat().format(job.duration || 0);\r\n this.notificationService.success(_('catalog.reindex-successful'), {\r\n count: job.result.indexedItemCount,\r\n time,\r\n });\r\n this.refresh();\r\n } else {\r\n this.notificationService.error(_('catalog.reindex-error'));\r\n }\r\n });\r\n });\r\n }\r\n\r\n runPendingSearchIndexUpdates() {\r\n this.dataService.product.runPendingSearchIndexUpdates().subscribe(value => {\r\n this.notificationService.info(_('catalog.running-search-index-updates'), {\r\n count: this.pendingSearchIndexUpdates,\r\n });\r\n this.pendingSearchIndexUpdates = 0;\r\n });\r\n }\r\n\r\n deleteProduct(productId: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response => (response ? this.dataService.product.deleteProduct(productId) : EMPTY)),\r\n // Short delay to allow the product to be removed from the search index before\r\n // refreshing.\r\n delay(500),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'Product',\r\n });\r\n this.refresh();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'Product',\r\n });\r\n },\r\n );\r\n }\r\n\r\n setLanguage(code: LanguageCode) {\r\n this.dataService.client.setContentLanguage(code).subscribe();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-left>\r\n <vdr-language-selector\r\n [availableLanguageCodes]=\"availableLanguages$ | async\"\r\n [currentLanguageCode]=\"languageCode$ | async\"\r\n (languageCodeChange)=\"setLanguage($event)\"\r\n ></vdr-language-selector>\r\n </vdr-ab-left>\r\n\r\n <vdr-ab-right>\r\n <div class=\"flex center\">\r\n <div class=\"mr2\">\r\n <clr-checkbox-wrapper>\r\n <input\r\n clrCheckbox\r\n type=\"checkbox\"\r\n id=\"auto-update\"\r\n [(ngModel)]=\"autoUpdateVariantNames\"\r\n />\r\n <label>{{ 'catalog.auto-update-product-variant-name' | translate }}</label>\r\n </clr-checkbox-wrapper>\r\n </div>\r\n <button\r\n *vdrIfPermissions=\"updatePermission\"\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"detailForm.pristine || detailForm.invalid\"\r\n >\r\n {{ 'common.update' | translate }}\r\n </button>\r\n </div>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n<form class=\"form\" [formGroup]=\"detailForm\" *ngIf=\"optionGroups$ | async as optionGroups\">\r\n <div formGroupName=\"optionGroups\" class=\"clr-row\">\r\n <div class=\"clr-col-12 clr-col-xl-6\" *ngFor=\"let optionGroup of getOptionGroups(); index as i\">\r\n <section class=\"card\" [formArrayName]=\"i\">\r\n <div class=\"card-header option-group-header\">\r\n <vdr-entity-info [entity]=\"optionGroup.value\"></vdr-entity-info>\r\n <div class=\"ml2\">{{ optionGroup.value.code }}</div>\r\n </div>\r\n <div class=\"card-block\">\r\n <vdr-form-field [label]=\"'common.name' | translate\" for=\"name\">\r\n <input\r\n [id]=\"'name-' + i\"\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </vdr-form-field>\r\n <vdr-form-field [label]=\"'common.code' | translate\" for=\"code\">\r\n <input\r\n [id]=\"'code-' + i\"\r\n type=\"text\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n formControlName=\"code\"\r\n />\r\n </vdr-form-field>\r\n </div>\r\n <section class=\"card-block\">\r\n <table class=\"facet-values-list table mt2 mb4\" formGroupName=\"options\">\r\n <thead>\r\n <tr>\r\n <th></th>\r\n <th>{{ 'common.name' | translate }}</th>\r\n <th>{{ 'common.code' | translate }}</th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n <tr\r\n class=\"facet-value\"\r\n *ngFor=\"let option of getOptions(optionGroup); let i = index\"\r\n [formGroupName]=\"i\"\r\n >\r\n <td class=\"align-middle\">\r\n <vdr-entity-info [entity]=\"option.value\"></vdr-entity-info>\r\n </td>\r\n <td class=\"align-middle\">\r\n <input\r\n type=\"text\"\r\n formControlName=\"name\"\r\n [readonly]=\"!(updatePermission | hasPermission)\"\r\n />\r\n </td>\r\n <td class=\"align-middle\"><input type=\"text\" formControlName=\"code\" /></td>\r\n </tr>\r\n </tbody>\r\n </table>\r\n </section>\r\n </section>\r\n </div>\r\n </div>\r\n</form>\r\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';\r\nimport { FormArray, FormBuilder, FormGroup } from '@angular/forms';\r\nimport { ActivatedRoute, Router } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n BaseDetailComponent,\r\n createUpdatedTranslatable,\r\n CustomFieldConfig,\r\n DataService,\r\n findTranslation,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n NotificationService,\r\n Permission,\r\n ProductOptionFragment,\r\n ProductOptionGroup,\r\n ProductOptionGroupFragment,\r\n ServerConfigService,\r\n UpdateProductOptionGroupInput,\r\n UpdateProductOptionInput,\r\n} from '@vendure/admin-ui/core';\r\nimport { combineLatest, forkJoin, Observable } from 'rxjs';\r\nimport { map, mergeMap, take } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\n\r\ntype ProductWithOptions = NonNullable<GetProductVariantOptionsQuery['product']>;\r\n\r\n@Component({\r\n selector: 'vdr-product-options-editor',\r\n templateUrl: './product-options-editor.component.html',\r\n styleUrls: ['./product-options-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ProductOptionsEditorComponent extends BaseDetailComponent<ProductWithOptions> implements OnInit {\r\n detailForm: FormGroup;\r\n optionGroups$: Observable<ProductWithOptions['optionGroups']>;\r\n languageCode$: Observable<LanguageCode>;\r\n availableLanguages$: Observable<LanguageCode[]>;\r\n optionGroupCustomFields: CustomFieldConfig[];\r\n optionCustomFields: CustomFieldConfig[];\r\n autoUpdateVariantNames = true;\r\n readonly updatePermission = [Permission.UpdateCatalog, Permission.UpdateProduct];\r\n\r\n constructor(\r\n protected route: ActivatedRoute,\r\n protected router: Router,\r\n protected serverConfigService: ServerConfigService,\r\n protected dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private formBuilder: FormBuilder,\r\n private changeDetector: ChangeDetectorRef,\r\n private notificationService: NotificationService,\r\n ) {\r\n super(route, router, serverConfigService, dataService);\r\n this.optionGroupCustomFields = this.getCustomFieldConfig('ProductOptionGroup');\r\n this.optionCustomFields = this.getCustomFieldConfig('ProductOption');\r\n }\r\n\r\n ngOnInit(): void {\r\n this.optionGroups$ = this.route.snapshot.data.entity.pipe(\r\n map((product: ProductWithOptions) => product.optionGroups),\r\n );\r\n this.detailForm = new FormGroup({\r\n optionGroups: new FormArray([]),\r\n });\r\n super.init();\r\n }\r\n\r\n getOptionGroups(): FormGroup[] {\r\n const optionGroups = this.detailForm.get('optionGroups');\r\n return (optionGroups as FormArray).controls as FormGroup[];\r\n }\r\n\r\n getOptions(optionGroup: FormGroup): FormGroup[] {\r\n const options = optionGroup.get('options');\r\n return (options as FormArray).controls as FormGroup[];\r\n }\r\n\r\n save() {\r\n if (this.detailForm.invalid || this.detailForm.pristine) {\r\n return;\r\n }\r\n // tslint:disable-next-line:no-non-null-assertion\r\n const $product = this.dataService.product.getProduct(this.id).mapSingle(data => data.product!);\r\n combineLatest(this.entity$, this.languageCode$, $product)\r\n .pipe(\r\n take(1),\r\n mergeMap(([{ optionGroups }, languageCode, product]) => {\r\n const updateOperations: Array<Observable<any>> = [];\r\n for (const optionGroupForm of this.getOptionGroups()) {\r\n if (optionGroupForm.get('name')?.dirty || optionGroupForm.get('code')?.dirty) {\r\n const optionGroupEntity = optionGroups.find(\r\n og => og.id === optionGroupForm.value.id,\r\n );\r\n if (optionGroupEntity) {\r\n const input = this.getUpdatedOptionGroup(\r\n optionGroupEntity,\r\n optionGroupForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.dataService.product.updateProductOptionGroup(input),\r\n );\r\n }\r\n }\r\n\r\n for (const optionForm of this.getOptions(optionGroupForm)) {\r\n if (optionForm.get('name')?.dirty || optionForm.get('code')?.dirty) {\r\n const optionGroup = optionGroups\r\n .find(og => og.id === optionGroupForm.value.id)\r\n ?.options.find(o => o.id === optionForm.value.id);\r\n if (optionGroup) {\r\n const input = this.getUpdatedOption(\r\n optionGroup,\r\n optionForm,\r\n languageCode,\r\n );\r\n updateOperations.push(\r\n this.productDetailService.updateProductOption(\r\n { ...input, autoUpdate: this.autoUpdateVariantNames },\r\n product,\r\n languageCode,\r\n ),\r\n );\r\n }\r\n }\r\n }\r\n }\r\n return forkJoin(updateOperations);\r\n }),\r\n )\r\n .subscribe(\r\n () => {\r\n this.detailForm.markAsPristine();\r\n this.changeDetector.markForCheck();\r\n this.notificationService.success(_('common.notify-update-success'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-update-error'), {\r\n entity: 'ProductOptionGroup',\r\n });\r\n },\r\n );\r\n }\r\n\r\n private getUpdatedOptionGroup(\r\n optionGroup: ProductOptionGroupFragment,\r\n optionGroupFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionGroupInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: optionGroup,\r\n updatedFields: optionGroupFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: optionGroup.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n private getUpdatedOption(\r\n option: ProductOptionFragment,\r\n optionFormGroup: FormGroup,\r\n languageCode: LanguageCode,\r\n ): UpdateProductOptionInput {\r\n const input = createUpdatedTranslatable({\r\n translatable: option,\r\n updatedFields: optionFormGroup.value,\r\n customFieldConfig: this.optionGroupCustomFields,\r\n languageCode,\r\n defaultTranslation: {\r\n languageCode,\r\n name: option.name || '',\r\n },\r\n });\r\n return input;\r\n }\r\n\r\n protected setFormValues(entity: ProductWithOptions, languageCode: LanguageCode): void {\r\n const groupsFormArray = new FormArray([]);\r\n for (const optionGroup of entity.optionGroups) {\r\n const groupTranslation = findTranslation(optionGroup, languageCode);\r\n const group = {\r\n id: optionGroup.id,\r\n createdAt: optionGroup.createdAt,\r\n updatedAt: optionGroup.updatedAt,\r\n code: optionGroup.code,\r\n name: groupTranslation ? groupTranslation.name : '',\r\n };\r\n const optionsFormArray = new FormArray([]);\r\n\r\n for (const option of optionGroup.options) {\r\n const optionTranslation = findTranslation(option, languageCode);\r\n const optionControl = this.formBuilder.group({\r\n id: option.id,\r\n createdAt: option.createdAt,\r\n updatedAt: option.updatedAt,\r\n code: option.code,\r\n name: optionTranslation ? optionTranslation.name : '',\r\n });\r\n optionsFormArray.push(optionControl);\r\n }\r\n\r\n const groupControl = this.formBuilder.group(group);\r\n groupControl.addControl('options', optionsFormArray);\r\n groupsFormArray.push(groupControl);\r\n }\r\n this.detailForm.setControl('optionGroups', groupsFormArray);\r\n }\r\n}\r\n","<ng-template vdrDialogTitle>\r\n {{ 'catalog.confirm-deletion-of-unused-variants-title' | translate }}\r\n</ng-template>\r\n{{ 'catalog.confirm-deletion-of-unused-variants-body' | translate }}\r\n<ul>\r\n <li *ngFor=\"let variant of variants\">{{ variant.name }} ({{ variant.sku }})</li>\r\n</ul>\r\n<ng-template vdrDialogButtons>\r\n <button type=\"button\" class=\"btn\" (click)=\"cancel()\">{{ 'common.cancel' | translate }}</button>\r\n <button type=\"submit\" (click)=\"confirm()\" class=\"btn btn-primary\">\r\n {{ 'common.confirm' | translate }}\r\n </button>\r\n</ng-template>\r\n","import { ChangeDetectionStrategy, Component } from '@angular/core';\r\nimport { Dialog, GetProductVariantOptionsQuery } from '@vendure/admin-ui/core';\r\n\r\n@Component({\r\n selector: 'vdr-confirm-variant-deletion-dialog',\r\n templateUrl: './confirm-variant-deletion-dialog.component.html',\r\n styleUrls: ['./confirm-variant-deletion-dialog.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n})\r\nexport class ConfirmVariantDeletionDialogComponent implements Dialog<boolean> {\r\n resolveWith: (result?: boolean) => void;\r\n variants: NonNullable<GetProductVariantOptionsQuery['product']>['variants'] = [];\r\n\r\n confirm() {\r\n this.resolveWith(true);\r\n }\r\n\r\n cancel() {\r\n this.resolveWith();\r\n }\r\n}\r\n","<vdr-action-bar>\r\n <vdr-ab-right>\r\n <button\r\n class=\"btn btn-primary\"\r\n (click)=\"save()\"\r\n [disabled]=\"!formValueChanged || getVariantsToAdd().length === 0\"\r\n >\r\n {{ 'common.add-new-variants' | translate: { count: getVariantsToAdd().length } }}\r\n </button>\r\n </vdr-ab-right>\r\n</vdr-action-bar>\r\n\r\n<div *ngFor=\"let group of optionGroups\" class=\"option-groups\">\r\n <div class=\"name\">\r\n <label>{{ 'catalog.option' | translate }}</label>\r\n <input clrInput [(ngModel)]=\"group.name\" name=\"name\" [readonly]=\"!group.isNew\" />\r\n </div>\r\n <div class=\"values\">\r\n <label>{{ 'catalog.option-values' | translate }}</label>\r\n <vdr-option-value-input\r\n #optionValueInputComponent\r\n [(ngModel)]=\"group.values\"\r\n (ngModelChange)=\"generateVariants()\"\r\n [groupName]=\"group.name\"\r\n [disabled]=\"group.name === ''\"\r\n ></vdr-option-value-input>\r\n </div>\r\n</div>\r\n<button\r\n class=\"btn btn-primary-outline btn-sm\"\r\n (click)=\"addOption()\"\r\n>\r\n <clr-icon shape=\"plus\"></clr-icon>\r\n {{ 'catalog.add-option' | translate }}\r\n</button>\r\n\r\n<div class=\"variants-preview\">\r\n <table class=\"table\">\r\n <thead>\r\n <tr>\r\n <th>{{ 'common.create' | translate }}</th>\r\n <th>{{ 'catalog.variant' | translate }}</th>\r\n <th>{{ 'catalog.sku' | translate }}</th>\r\n <th>{{ 'catalog.price' | translate }}</th>\r\n <th>{{ 'catalog.stock-on-hand' | translate }}</th>\r\n <th></th>\r\n </tr>\r\n </thead>\r\n <tr *ngFor=\"let variant of generatedVariants\" [class.disabled]=\"!variant.enabled || variant.existing\">\r\n <td>\r\n <input\r\n type=\"checkbox\"\r\n *ngIf=\"!variant.existing\"\r\n [(ngModel)]=\"variant.enabled\"\r\n name=\"enabled\"\r\n clrCheckbox\r\n (ngModelChange)=\"formValueChanged = true\"\r\n />\r\n </td>\r\n <td>\r\n {{ getVariantName(variant) | translate }}\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"text\"\r\n [(ngModel)]=\"variant.sku\"\r\n [placeholder]=\"'catalog.sku' | translate\"\r\n name=\"sku\"\r\n required\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.sku }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <vdr-currency-input\r\n clrInput\r\n [(ngModel)]=\"variant.price\"\r\n name=\"price\"\r\n [currencyCode]=\"currencyCode\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n ></vdr-currency-input>\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.price | localeCurrency: currencyCode }}</span>\r\n </td>\r\n <td>\r\n <clr-input-container *ngIf=\"!variant.existing\">\r\n <input\r\n clrInput\r\n type=\"number\"\r\n [(ngModel)]=\"variant.stock\"\r\n name=\"stock\"\r\n min=\"0\"\r\n step=\"1\"\r\n (ngModelChange)=\"onFormChanged(variant)\"\r\n />\r\n </clr-input-container>\r\n <span *ngIf=\"variant.existing\">{{ variant.stock }}</span>\r\n </td>\r\n <td>\r\n <vdr-dropdown *ngIf=\"variant.productVariantId as productVariantId\">\r\n <button class=\"icon-button\" vdrDropdownTrigger>\r\n <clr-icon shape=\"ellipsis-vertical\"></clr-icon>\r\n </button>\r\n <vdr-dropdown-menu vdrPosition=\"bottom-right\">\r\n <button\r\n type=\"button\"\r\n class=\"delete-button\"\r\n (click)=\"deleteVariant(productVariantId)\"\r\n vdrDropdownItem\r\n >\r\n <clr-icon shape=\"trash\" class=\"is-danger\"></clr-icon>\r\n {{ 'common.delete' | translate }}\r\n </button>\r\n </vdr-dropdown-menu>\r\n </vdr-dropdown>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n","import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';\r\nimport { ActivatedRoute } from '@angular/router';\r\nimport { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';\r\nimport {\r\n CreateProductOptionGroupMutation,\r\n CreateProductOptionInput,\r\n CurrencyCode,\r\n DataService,\r\n DeactivateAware,\r\n getDefaultUiLanguage,\r\n GetProductVariantOptionsQuery,\r\n LanguageCode,\r\n ModalService,\r\n NotificationService,\r\n ProductOptionGroupWithOptionsFragment,\r\n} from '@vendure/admin-ui/core';\r\nimport { normalizeString } from '@vendure/common/lib/normalize-string';\r\nimport { pick } from '@vendure/common/lib/pick';\r\nimport { generateAllCombinations, notNullOrUndefined } from '@vendure/common/lib/shared-utils';\r\nimport { unique } from '@vendure/common/lib/unique';\r\nimport { EMPTY, forkJoin, Observable, of } from 'rxjs';\r\nimport { filter, map, mergeMap, switchMap } from 'rxjs/operators';\r\n\r\nimport { ProductDetailService } from '../../providers/product-detail/product-detail.service';\r\nimport { ConfirmVariantDeletionDialogComponent } from '../confirm-variant-deletion-dialog/confirm-variant-deletion-dialog.component';\r\n\r\nexport class GeneratedVariant {\r\n isDefault: boolean;\r\n options: Array<{ name: string; id?: string }>;\r\n productVariantId?: string;\r\n enabled: boolean;\r\n existing: boolean;\r\n sku: string;\r\n price: number;\r\n stock: number;\r\n\r\n constructor(config: Partial<GeneratedVariant>) {\r\n for (const key of Object.keys(config)) {\r\n this[key] = config[key];\r\n }\r\n }\r\n}\r\n\r\n@Component({\r\n selector: 'vdr-product-variants-editor',\r\n templateUrl: './product-variants-editor.component.html',\r\n styleUrls: ['./product-variants-editor.component.scss'],\r\n changeDetection: ChangeDetectionStrategy.Default,\r\n})\r\nexport class ProductVariantsEditorComponent implements OnInit, DeactivateAware {\r\n formValueChanged = false;\r\n generatedVariants: GeneratedVariant[] = [];\r\n optionGroups: Array<{\r\n id?: string;\r\n isNew: boolean;\r\n name: string;\r\n values: Array<{\r\n id?: string;\r\n name: string;\r\n locked: boolean;\r\n }>;\r\n }>;\r\n product: NonNullable<GetProductVariantOptionsQuery['product']>;\r\n currencyCode: CurrencyCode;\r\n private languageCode: LanguageCode;\r\n\r\n constructor(\r\n private route: ActivatedRoute,\r\n private dataService: DataService,\r\n private productDetailService: ProductDetailService,\r\n private notificationService: NotificationService,\r\n private modalService: ModalService,\r\n ) {}\r\n\r\n ngOnInit() {\r\n this.initOptionsAndVariants();\r\n this.languageCode =\r\n (this.route.snapshot.paramMap.get('lang') as LanguageCode) || getDefaultUiLanguage();\r\n this.dataService.settings.getActiveChannel().single$.subscribe(data => {\r\n this.currencyCode = data.activeChannel.currencyCode;\r\n });\r\n }\r\n\r\n onFormChanged(variantInfo: GeneratedVariant) {\r\n this.formValueChanged = true;\r\n variantInfo.enabled = true;\r\n }\r\n\r\n canDeactivate(): boolean {\r\n return !this.formValueChanged;\r\n }\r\n\r\n getVariantsToAdd() {\r\n return this.generatedVariants.filter(v => !v.existing && v.enabled);\r\n }\r\n\r\n getVariantName(variant: GeneratedVariant) {\r\n return variant.options.length === 0\r\n ? _('catalog.default-variant')\r\n : variant.options.map(o => o.name).join(' ');\r\n }\r\n\r\n addOption() {\r\n this.optionGroups.push({\r\n isNew: true,\r\n name: '',\r\n values: [],\r\n });\r\n }\r\n\r\n generateVariants() {\r\n const groups = this.optionGroups.map(g => g.values);\r\n const previousVariants = this.generatedVariants;\r\n const generatedVariantFactory = (\r\n isDefault: boolean,\r\n options: GeneratedVariant['options'],\r\n existingVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n prototypeVariant?: NonNullable<GetProductVariantOptionsQuery['product']>['variants'][number],\r\n ): GeneratedVariant => {\r\n const prototype = this.getVariantPrototype(options, previousVariants);\r\n return new GeneratedVariant({\r\n enabled: true,\r\n existing: !!existingVariant,\r\n productVariantId: existingVariant?.id,\r\n isDefault,\r\n options,\r\n price: existingVariant?.price ?? prototypeVariant?.price ?? prototype.price,\r\n sku: existingVariant?.sku ?? prototypeVariant?.sku ?? prototype.sku,\r\n stock: existingVariant?.stockOnHand ?? prototypeVariant?.stockOnHand ?? prototype.stock,\r\n });\r\n };\r\n this.generatedVariants = groups.length\r\n ? generateAllCombinations(groups).map(options => {\r\n const existingVariant = this.product.variants.find(v =>\r\n this.optionsAreEqual(v.options, options),\r\n );\r\n const prototypeVariant = this.product.variants.find(v =>\r\n this.optionsAreSubset(v.options, options),\r\n );\r\n return generatedVariantFactory(false, options, existingVariant, prototypeVariant);\r\n })\r\n : [generatedVariantFactory(true, [], this.product.variants[0])];\r\n }\r\n\r\n /**\r\n * Returns one of the existing variants to base the newly-generated variant's\r\n * details off.\r\n */\r\n private getVariantPrototype(\r\n options: GeneratedVariant['options'],\r\n previousVariants: GeneratedVariant[],\r\n ): Pick<GeneratedVariant, 'sku' | 'price' | 'stock'> {\r\n const variantsWithSimilarOptions = previousVariants.filter(v =>\r\n options.map(o => o.name).filter(name => v.options.map(o => o.name).includes(name)),\r\n );\r\n if (variantsWithSimilarOptions.length) {\r\n return pick(previousVariants[0], ['sku', 'price', 'stock']);\r\n }\r\n return {\r\n sku: '',\r\n price: 0,\r\n stock: 0,\r\n };\r\n }\r\n\r\n deleteVariant(id: string) {\r\n this.modalService\r\n .dialog({\r\n title: _('catalog.confirm-delete-product-variant'),\r\n buttons: [\r\n { type: 'secondary', label: _('common.cancel') },\r\n { type: 'danger', label: _('common.delete'), returnValue: true },\r\n ],\r\n })\r\n .pipe(\r\n switchMap(response =>\r\n response ? this.productDetailService.deleteProductVariant(id, this.product.id) : EMPTY,\r\n ),\r\n switchMap(() => this.reFetchProduct(null)),\r\n )\r\n .subscribe(\r\n () => {\r\n this.notificationService.success(_('common.notify-delete-success'), {\r\n entity: 'ProductVariant',\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n err => {\r\n this.notificationService.error(_('common.notify-delete-error'), {\r\n entity: 'ProductVariant',\r\n });\r\n },\r\n );\r\n }\r\n\r\n save() {\r\n const newOptionGroups = this.optionGroups\r\n .filter(og => og.isNew)\r\n .map(og => ({\r\n name: og.name,\r\n values: [],\r\n }));\r\n\r\n this.checkUniqueSkus()\r\n .pipe(\r\n mergeMap(() => this.confirmDeletionOfObsoleteVariants()),\r\n mergeMap(() =>\r\n this.productDetailService.createProductOptionGroups(newOptionGroups, this.languageCode),\r\n ),\r\n mergeMap(createdOptionGroups => this.addOptionGroupsToProduct(createdOptionGroups)),\r\n mergeMap(createdOptionGroups => this.addNewOptionsToGroups(createdOptionGroups)),\r\n mergeMap(groupsIds => this.fetchOptionGroups(groupsIds)),\r\n mergeMap(groups => this.createNewProductVariants(groups)),\r\n mergeMap(res => this.deleteObsoleteVariants(res.createProductVariants)),\r\n mergeMap(variants => this.reFetchProduct(variants)),\r\n )\r\n .subscribe({\r\n next: variants => {\r\n this.formValueChanged = false;\r\n this.notificationService.success(_('catalog.created-new-variants-success'), {\r\n count: variants.length,\r\n });\r\n this.initOptionsAndVariants();\r\n },\r\n });\r\n }\r\n\r\n private checkUniqueSkus() {\r\n const withDuplicateSkus = this.generatedVariants.filter((variant, index) => {\r\n return this.generatedVariants.find(gv => gv.sku.trim() === variant.sku.trim() && gv !== variant);\r\n });\r\n if (withDuplicateSkus.length) {\r\n return this.modalService\r\n .dialog({\r\n title: _('catalog.duplicate-sku-warning'),\r\n body: unique(withDuplicateSkus.map(v => `${v.sku}`)).join(', '),\r\n buttons: [{ label: _('common.close'), returnValue: false, type: 'primary' }],\r\n })\r\n .pipe(mergeMap(res => EMPTY));\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private confirmDeletionOfObsoleteVariants(): Observable<boolean> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n return this.modalService\r\n .fromComponent(ConfirmVariantDeletionDialogComponent, {\r\n locals: {\r\n variants: obsoleteVariants,\r\n },\r\n })\r\n .pipe(\r\n mergeMap(res => {\r\n return res === true ? of(true) : EMPTY;\r\n }),\r\n );\r\n } else {\r\n return of(true);\r\n }\r\n }\r\n\r\n private getObsoleteVariants() {\r\n return this.product.variants.filter(\r\n variant => !this.generatedVariants.find(gv => gv.productVariantId === variant.id),\r\n );\r\n }\r\n\r\n private hasOnlyDefaultVariant(product: NonNullable<GetProductVariantOptionsQuery['product']>): boolean {\r\n return product.variants.length === 1 && product.optionGroups.length === 0;\r\n }\r\n\r\n private addOptionGroupsToProduct(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<Array<CreateProductOptionGroupMutation['createProductOptionGroup']>> {\r\n if (createdOptionGroups.length) {\r\n return forkJoin(\r\n createdOptionGroups.map(optionGroup => {\r\n return this.dataService.product.addOptionGroupToProduct({\r\n productId: this.product.id,\r\n optionGroupId: optionGroup.id,\r\n });\r\n }),\r\n ).pipe(map(() => createdOptionGroups));\r\n } else {\r\n return of([]);\r\n }\r\n }\r\n\r\n private addNewOptionsToGroups(\r\n createdOptionGroups: Array<CreateProductOptionGroupMutation['createProductOptionGroup']>,\r\n ): Observable<string[]> {\r\n const newOptions: CreateProductOptionInput[] = this.optionGroups\r\n .map(og => {\r\n const createdGroup = createdOptionGroups.find(cog => cog.name === og.name);\r\n const productOptionGroupId = createdGroup ? createdGroup.id : og.id;\r\n if (!productOptionGroupId) {\r\n throw new Error('Could not get a productOptionGroupId');\r\n }\r\n return og.values\r\n .filter(v => !v.locked)\r\n .map(v => ({\r\n productOptionGroupId,\r\n code: normalizeString(v.name, '-'),\r\n translations: [{ name: v.name, languageCode: this.languageCode }],\r\n }));\r\n })\r\n .reduce((flat, options) => [...flat, ...options], []);\r\n\r\n const allGroupIds = [\r\n ...createdOptionGroups.map(g => g.id),\r\n ...this.optionGroups.map(g => g.id).filter(notNullOrUndefined),\r\n ];\r\n\r\n if (newOptions.length) {\r\n return forkJoin(newOptions.map(input => this.dataService.product.addOptionToGroup(input))).pipe(\r\n map(() => allGroupIds),\r\n );\r\n } else {\r\n return of(allGroupIds);\r\n }\r\n }\r\n\r\n private fetchOptionGroups(groupsIds: string[]): Observable<ProductOptionGroupWithOptionsFragment[]> {\r\n return forkJoin(\r\n groupsIds.map(id =>\r\n this.dataService.product\r\n .getProductOptionGroup(id)\r\n .mapSingle(data => data.productOptionGroup)\r\n .pipe(filter(notNullOrUndefined)),\r\n ),\r\n );\r\n }\r\n\r\n private createNewProductVariants(groups: ProductOptionGroupWithOptionsFragment[]) {\r\n const options = groups\r\n .filter(notNullOrUndefined)\r\n .map(og => og.options)\r\n .reduce((flat, o) => [...flat, ...o], []);\r\n const variants = this.generatedVariants\r\n .filter(v => v.enabled && !v.existing)\r\n .map(v => ({\r\n price: v.price,\r\n sku: v.sku,\r\n stock: v.stock,\r\n optionIds: v.options\r\n .map(name => options.find(o => o.name === name.name))\r\n .filter(notNullOrUndefined)\r\n .map(o => o.id),\r\n }));\r\n return this.productDetailService.createProductVariants(\r\n this.product,\r\n variants,\r\n options,\r\n this.languageCode,\r\n );\r\n }\r\n\r\n private deleteObsoleteVariants<T>(input: T): Observable<T | T[]> {\r\n const obsoleteVariants = this.getObsoleteVariants();\r\n if (obsoleteVariants.length) {\r\n const deleteOperations = obsoleteVariants.map(v =>\r\n this.dataService.product.deleteProductVariant(v.id).pipe(map(() => input)),\r\n );\r\n return forkJoin(...deleteOperations);\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n private reFetchProduct<T>(input: T): Observable<T> {\r\n // Re-fetch the Product to force an update to the view.\r\n const id = this.route.snapshot.paramMap.get('id');\r\n if (id) {\r\n return this.dataService.product.getProduct(id).single$.pipe(map(() => input));\r\n } else {\r\n return of(input);\r\n }\r\n }\r\n\r\n initOptionsAndVariants() {\r\n this.dataService.product\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .getProductVariantsOptions(this.route.snapshot.paramMap.get('id')!)\r\n // tslint:disable-next-line:no-non-null-assertion\r\n .mapSingle(({ product }) => product!)\r\n .subscribe(p => {\r\n this.product = p;\r\n this.optionGroups = p.optionGroups.map(og => {\r\n return {\r\n id: og.id,\r\n isNew: false,\r\n name: og.name,\r\n values: og.options.map(o => ({\r\n id: o.id,\r\n name: o.name,\r\n locked: true,\r\n })),\r\n };\r\n });\r\n this.generateVariants();\r\n });\r\n }\r\n\r\n private optionsAreEqual(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(a) === this.toOptionString(b);\r\n }\r\n\r\n private optionsAreSubset(a: Array<{ name: string }>, b: Array<{ name: string }>): boolean {\r\n return this.toOptionString(b).includes(this.toOptionString(a));\r\n }\r\n\r\n private toOptionString(o: Array<{ name: string }>): string {\r\n return o\r\n .map(x => x.name)\r\n .sort()\r\n .join('|');\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\r\nimport { Router } from '@angular/router';\r\nimport { AssetFragment, AssetType, BaseEntityResolver, DataService } from '@vendure/admin-ui/core';\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class AssetResolver extends BaseEntityResolver<AssetFragment> {\r\n constructor(router: Router, dataService: DataService) {\r\n super(\r\n router,\r\n {\r\n __typename: 'Asset' as const,\r\n id: '',\r\n createdAt: '',\r\n updatedAt: '',\r\n name: '',\r\n type: AssetType.IMAGE,\r\n fileSize: 0,\r\n mimeType: '',\r\n width: 0,\r\n height: 0,\r\n source: '',\r\n preview: '',\r\n focalPoint: null,\r\n },\r\n id => dataService.product.getAsset(id).mapStream(data => data.asset),\r\n );\r\n }\r\n}\r\n","import { Injectable } from '@angular/core';\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 { ProductSearchInputComponent } from './components/product-search-input/product-search-input.component';\r\nimport { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';\r\nimport { ProductVariantsListComponent } from './components/product-variants-list/product-variants-list.component';\r\nimport { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';\r\nimport { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';\r\nimport { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';\r\n\r\nconst CATALOG_COMPONENTS = [\r\n ProductListComponent,\r\n ProductDetailComponent,\r\n FacetListComponent,\r\n FacetDetailComponent,\r\n GenerateProductVariantsComponent,\r\n ProductVariantsListComponent,\r\n ApplyFacetDialogComponent,\r\n AssetListComponent,\r\n AssetsComponent,\r\n VariantPriceDetailComponent,\r\n CollectionListComponent,\r\n CollectionDetailComponent,\r\n CollectionTreeComponent,\r\n CollectionTreeNodeComponent,\r\n CollectionContentsComponent,\r\n ProductVariantsTableComponent,\r\n ProductSearchInputComponent,\r\n OptionValueInputComponent,\r\n UpdateProductOptionDialogComponent,\r\n ProductVariantsEditorComponent,\r\n AssignProductsToChannelDialogComponent,\r\n AssetDetailComponent,\r\n ConfirmVariantDeletionDialogComponent,\r\n ProductOptionsEditorComponent,\r\n];\r\n\r\n@NgModule({\r\n imports: [SharedModule, RouterModule.forChild(catalogRoutes)],\r\n exports: [...CATALOG_COMPONENTS],\r\n declarations: [...CATALOG_COMPONENTS],\r\n})\r\nexport class CatalogModule {}\r\n"],"sourceRoot":"webpack:///","file":"349.6baced2d0430de3d.js"}
|