Browse Source

refactor(admin-ui): Extract channel assign/remove logic

Michael Bromley 2 years ago
parent
commit
c989e2ba01
29 changed files with 536 additions and 455 deletions
  1. 17 17
      packages/admin-ui/i18n-coverage.json
  2. 4 6
      packages/admin-ui/src/lib/catalog/src/catalog.module.ts
  3. 0 1
      packages/admin-ui/src/lib/catalog/src/components/asset-detail/asset-detail.component.ts
  4. 0 24
      packages/admin-ui/src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html
  5. 11 1
      packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.scss
  6. 44 164
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list-bulk-actions.ts
  7. 38 44
      packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list-bulk-actions.ts
  8. 17 70
      packages/admin-ui/src/lib/catalog/src/components/product-list/product-list-bulk-actions.ts
  9. 1 1
      packages/admin-ui/src/lib/catalog/src/public_api.ts
  10. 214 5
      packages/admin-ui/src/lib/core/src/common/utilities/bulk-action-utils.ts
  11. 40 0
      packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html
  12. 0 0
      packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.scss
  13. 2 1
      packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.ts
  14. 3 3
      packages/admin-ui/src/lib/core/src/shared/components/simple-dialog/simple-dialog.component.html
  15. 2 0
      packages/admin-ui/src/lib/core/src/shared/shared.module.ts
  16. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  17. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  18. 11 10
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  19. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  20. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  21. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  22. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  23. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  24. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  25. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  26. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  27. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  28. 10 9
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json
  29. 12 0
      packages/admin-ui/src/lib/static/styles/global/_buttons.scss

+ 17 - 17
packages/admin-ui/i18n-coverage.json

@@ -1,69 +1,69 @@
 {
-  "generatedOn": "2023-06-01T14:33:50.530Z",
-  "lastCommit": "20d205bfb09cc05f848ae71358e45c16eeda665b",
+  "generatedOn": "2023-06-02T10:15:42.053Z",
+  "lastCommit": "7e5e5d5db56a57946f8ba699311680cb3defc85c",
   "translationStatus": {
     "cs": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 547,
-      "percentage": 76
+      "percentage": 75
     },
     "de": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 530,
       "percentage": 73
     },
     "en": {
-      "tokenCount": 724,
-      "translatedCount": 724,
+      "tokenCount": 725,
+      "translatedCount": 723,
       "percentage": 100
     },
     "es": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 572,
       "percentage": 79
     },
     "fr": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 567,
       "percentage": 78
     },
     "it": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 571,
       "percentage": 79
     },
     "pl": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 381,
       "percentage": 53
     },
     "pt_BR": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 545,
       "percentage": 75
     },
     "pt_PT": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 580,
       "percentage": 80
     },
     "ru": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 570,
       "percentage": 79
     },
     "uk": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 570,
       "percentage": 79
     },
     "zh_Hans": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 516,
       "percentage": 71
     },
     "zh_Hant": {
-      "tokenCount": 724,
+      "tokenCount": 725,
       "translatedCount": 361,
       "percentage": 50
     }

+ 4 - 6
packages/admin-ui/src/lib/catalog/src/catalog.module.ts

@@ -20,7 +20,6 @@ import { AssetDetailComponent } from './components/asset-detail/asset-detail.com
 import { AssetListComponent } from './components/asset-list/asset-list.component';
 import { AssetsComponent } from './components/assets/assets.component';
 import { AssignProductsToChannelDialogComponent } from './components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';
-import { AssignToChannelDialogComponent } from './components/assign-to-channel-dialog/assign-to-channel-dialog.component';
 import { BulkAddFacetValuesDialogComponent } from './components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';
 import { CollectionContentsComponent } from './components/collection-contents/collection-contents.component';
 import { CollectionDataTableComponent } from './components/collection-data-table/collection-data-table.component';
@@ -59,13 +58,13 @@ import { ProductListComponent } from './components/product-list/product-list.com
 import { ProductOptionsEditorComponent } from './components/product-options-editor/product-options-editor.component';
 import { ProductVariantDetailComponent } from './components/product-variant-detail/product-variant-detail.component';
 import { ProductVariantListComponent } from './components/product-variant-list/product-variant-list.component';
+import { ProductVariantQuickJumpComponent } from './components/product-variant-quick-jump/product-variant-quick-jump.component';
 import { ProductVariantsEditorComponent } from './components/product-variants-editor/product-variants-editor.component';
 import { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';
+import { StockLocationDetailComponent } from './components/stock-location-detail/stock-location-detail.component';
+import { StockLocationListComponent } from './components/stock-location-list/stock-location-list.component';
 import { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';
 import { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';
-import { ProductVariantQuickJumpComponent } from './components/product-variant-quick-jump/product-variant-quick-jump.component';
-import { StockLocationListComponent } from './components/stock-location-list/stock-location-list.component';
-import { StockLocationDetailComponent } from './components/stock-location-detail/stock-location-detail.component';
 
 const CATALOG_COMPONENTS = [
     ProductListComponent,
@@ -91,7 +90,6 @@ const CATALOG_COMPONENTS = [
     ConfirmVariantDeletionDialogComponent,
     ProductOptionsEditorComponent,
     BulkAddFacetValuesDialogComponent,
-    AssignToChannelDialogComponent,
     CollectionDataTableComponent,
     CollectionBreadcrumbPipe,
     MoveCollectionsDialogComponent,
@@ -131,10 +129,10 @@ export class CatalogModule {
         bulkActionRegistryService.registerBulkAction(removeFacetsFromChannelBulkAction);
         bulkActionRegistryService.registerBulkAction(deleteFacetsBulkAction);
 
+        bulkActionRegistryService.registerBulkAction(moveCollectionsBulkAction);
         bulkActionRegistryService.registerBulkAction(assignCollectionsToChannelBulkAction);
         bulkActionRegistryService.registerBulkAction(removeCollectionsFromChannelBulkAction);
         bulkActionRegistryService.registerBulkAction(deleteCollectionsBulkAction);
-        bulkActionRegistryService.registerBulkAction(moveCollectionsBulkAction);
 
         pageService.registerPageTab({
             location: 'product-list',

+ 0 - 1
packages/admin-ui/src/lib/catalog/src/components/asset-detail/asset-detail.component.ts

@@ -2,7 +2,6 @@ import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/
 import { FormControl, FormGroup, UntypedFormBuilder } from '@angular/forms';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
-    Asset,
     ASSET_FRAGMENT,
     AssetDetailQueryDocument,
     AssetDetailQueryQuery,

+ 0 - 24
packages/admin-ui/src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html

@@ -1,24 +0,0 @@
-<ng-template vdrDialogTitle>
-    {{ 'catalog.assign-to-channel' | translate }}
-</ng-template>
-<clr-input-container class="mb-4">
-    <label>{{ 'common.channel' | translate }}</label>
-    <vdr-channel-assignment-control
-        clrInput
-        [multiple]="false"
-        [includeDefaultChannel]="false"
-        [formControl]="selectedChannelIdControl"
-    ></vdr-channel-assignment-control>
-</clr-input-container>
-
-<ng-template vdrDialogButtons>
-    <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
-    <button type="submit" (click)="assign()" [disabled]="!selectedChannel" class="btn btn-primary">
-        <ng-template [ngIf]="selectedChannel" [ngIfElse]="noSelection">
-            {{ 'catalog.assign-to-named-channel' | translate: { channelCode: selectedChannel?.code } }}
-        </ng-template>
-        <ng-template #noSelection>
-            {{ 'catalog.no-channel-selected' | translate }}
-        </ng-template>
-    </button>
-</ng-template>

+ 11 - 1
packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.scss

@@ -1,6 +1,16 @@
+@import 'variables';
+
 .bulk-actions {
-    margin-left: calc(var(--space-unit) * 10);
+    margin-left: calc(var(--space-unit) * 6);
+    @media screen and (min-width: $breakpoint-medium) {
+        margin-left: calc(var(--space-unit) * 9.5);
+    }
+    @media screen and (min-width: $breakpoint-large) {
+        margin-left: calc(var(--space-unit) * 11.5);
+    }
+    background-color: var(--color-surface-bg);
 }
+
 .drag-handle {
     cursor: grab;
 }

+ 44 - 164
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list-bulk-actions.ts

@@ -1,88 +1,43 @@
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BulkAction,
-    currentChannelIsNotDefault,
+    createBulkAssignToChannelAction,
+    createBulkDeleteAction,
+    createBulkRemoveFromChannelAction,
     DataService,
-    DeletionResult,
-    getChannelCodeFromUserStatus,
-    isMultiChannel,
+    GetCollectionListQuery,
+    ItemOf,
     ModalService,
     MoveCollectionInput,
     NotificationService,
     Permission,
 } from '@vendure/admin-ui/core';
-import { unique } from '@vendure/common/lib/unique';
-import { EMPTY, from, of } from 'rxjs';
-import { mapTo, switchMap } from 'rxjs/operators';
-
-import { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';
+import { EMPTY } from 'rxjs';
+import { map, switchMap } from 'rxjs/operators';
 import { CollectionPartial } from '../collection-tree/collection-tree.types';
 import { MoveCollectionsDialogComponent } from '../move-collections-dialog/move-collections-dialog.component';
 
 import { CollectionListComponent } from './collection-list.component';
 
-export const deleteCollectionsBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {
+export const deleteCollectionsBulkAction = createBulkDeleteAction<
+    ItemOf<GetCollectionListQuery, 'collections'>
+>({
     location: 'collection-list',
-    label: _('common.delete'),
-    icon: 'trash',
-    iconClass: 'is-danger',
     requiresPermission: userPermissions =>
         userPermissions.includes(Permission.DeleteCollection) ||
         userPermissions.includes(Permission.DeleteCatalog),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-        const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
-
-        modalService
-            .dialog({
-                title: _('catalog.confirm-bulk-delete-collections'),
-                translationVars: {
-                    count: selection.length,
-                },
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(response =>
-                    response
-                        ? dataService.collection.deleteCollections(unique(selection.map(c => c.id)))
-                        : EMPTY,
-                ),
-            )
-            .subscribe(result => {
-                let deleted = 0;
-                const errors: string[] = [];
-                for (const item of result.deleteCollections) {
-                    if (item.result === DeletionResult.DELETED) {
-                        deleted++;
-                    } else if (item.message) {
-                        errors.push(item.message);
-                    }
-                }
-                if (0 < deleted) {
-                    notificationService.success(_('catalog.notify-bulk-delete-collections-success'), {
-                        count: deleted,
-                    });
-                }
-                if (0 < errors.length) {
-                    notificationService.error(errors.join('\n'));
-                }
-                hostComponent.refresh();
-                clearSelection();
-            });
-    },
-};
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.collection.deleteCollections(ids).pipe(map(res => res.deleteCollections)),
+});
 
 export const moveCollectionsBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {
     location: 'collection-list',
     label: _('catalog.move-collections'),
-    icon: 'layers',
+    icon: 'drag-handle',
     requiresPermission: userPermissions =>
         userPermissions.includes(Permission.UpdateCatalog) ||
-        userPermissions.includes(Permission.UpdateProduct),
+        userPermissions.includes(Permission.UpdateCollection),
     onClick: ({ injector, selection, hostComponent, clearSelection }) => {
         const modalService = injector.get(ModalService);
         const dataService = injector.get(DataService);
@@ -116,111 +71,36 @@ export const moveCollectionsBulkAction: BulkAction<CollectionPartial, Collection
     },
 };
 
-export const assignCollectionsToChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {
+export const assignCollectionsToChannelBulkAction = createBulkAssignToChannelAction<
+    ItemOf<GetCollectionListQuery, 'collections'>
+>({
     location: 'collection-list',
-    label: _('catalog.assign-to-channel'),
-    icon: 'layers',
     requiresPermission: userPermissions =>
         userPermissions.includes(Permission.UpdateCatalog) ||
-        userPermissions.includes(Permission.UpdateProduct),
-    isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-        const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
-        modalService
-            .fromComponent(AssignToChannelDialogComponent, {
-                size: 'md',
-                locals: {},
+        userPermissions.includes(Permission.UpdateCollection),
+    getItemName: item => item.name,
+    bulkAssignToChannel: (dataService, collectionIds, channelId) =>
+        dataService.collection
+            .assignCollectionsToChannel({
+                collectionIds,
+                channelId,
             })
-            .pipe(
-                switchMap(result => {
-                    if (result) {
-                        return dataService.collection
-                            .assignCollectionsToChannel({
-                                collectionIds: selection.map(c => c.id),
-                                channelId: result.id,
-                            })
-                            .pipe(mapTo(result));
-                    } else {
-                        return EMPTY;
-                    }
-                }),
-            )
-            .subscribe(result => {
-                notificationService.success(_('catalog.assign-collections-to-channel-success'), {
-                    count: selection.length,
-                    channelCode: result.code,
-                });
-                clearSelection();
-            });
-    },
-};
-
-export const removeCollectionsFromChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> =
-    {
-        location: 'collection-list',
-        label: _('catalog.remove-from-channel'),
-        requiresPermission: userPermissions =>
-            userPermissions.includes(Permission.UpdateChannel) ||
-            userPermissions.includes(Permission.UpdateProduct),
-        getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),
-        icon: 'layers',
-        iconClass: 'is-warning',
-        isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),
-        onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-            const modalService = injector.get(ModalService);
-            const dataService = injector.get(DataService);
-            const notificationService = injector.get(NotificationService);
-            const activeChannelId$ = dataService.client
-                .userStatus()
-                .mapSingle(({ userStatus }) => userStatus.activeChannelId);
+            .pipe(map(res => res.assignCollectionsToChannel)),
+});
 
-            from(getChannelCodeFromUserStatus(injector.get(DataService)))
-                .pipe(
-                    switchMap(({ channelCode }) =>
-                        modalService.dialog({
-                            title: _('catalog.remove-from-channel'),
-                            translationVars: {
-                                channelCode,
-                            },
-                            buttons: [
-                                { type: 'secondary', label: _('common.cancel') },
-                                {
-                                    type: 'danger',
-                                    label: _('common.remove'),
-                                    returnValue: true,
-                                },
-                            ],
-                        }),
-                    ),
-                    switchMap(res =>
-                        res
-                            ? activeChannelId$.pipe(
-                                  switchMap(activeChannelId =>
-                                      activeChannelId
-                                          ? dataService.collection.removeCollectionsFromChannel({
-                                                channelId: activeChannelId,
-                                                collectionIds: selection.map(c => c.id),
-                                            })
-                                          : EMPTY,
-                                  ),
-                                  mapTo(true),
-                              )
-                            : of(false),
-                    ),
-                )
-                .subscribe(removed => {
-                    if (removed) {
-                        clearSelection();
-                        notificationService.success(
-                            _('catalog.notify-remove-collections-from-channel-success'),
-                            {
-                                count: selection.length,
-                            },
-                        );
-                        hostComponent.refresh();
-                    }
-                });
-        },
-    };
+export const removeCollectionsFromChannelBulkAction = createBulkRemoveFromChannelAction<
+    ItemOf<GetCollectionListQuery, 'collections'>
+>({
+    location: 'collection-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.DeleteCatalog) ||
+        userPermissions.includes(Permission.DeleteCollection),
+    getItemName: item => item.name,
+    bulkRemoveFromChannel: (dataService, collectionIds, channelId) =>
+        dataService.collection
+            .removeCollectionsFromChannel({
+                channelId: channelId,
+                collectionIds,
+            })
+            .pipe(map(res => res.removeCollectionsFromChannel)),
+});

+ 38 - 44
packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list-bulk-actions.ts

@@ -1,22 +1,23 @@
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BulkAction,
+    createBulkAssignToChannelAction,
     createBulkDeleteAction,
+    createBulkRemoveFromChannelAction,
     currentChannelIsNotDefault,
     DataService,
     getChannelCodeFromUserStatus,
     GetFacetListQuery,
-    isMultiChannel,
     ItemOf,
     ModalService,
     NotificationService,
     Permission,
+    RemoveFacetFromChannelResult,
+    RemoveFacetsFromChannelMutation,
 } from '@vendure/admin-ui/core';
 import { unique } from '@vendure/common/lib/unique';
 import { EMPTY, of } from 'rxjs';
-import { map, mapTo, switchMap } from 'rxjs/operators';
-
-import { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';
+import { map, switchMap } from 'rxjs/operators';
 
 import { FacetListComponent } from './facet-list.component';
 
@@ -31,51 +32,44 @@ export const deleteFacetsBulkAction = createBulkDeleteAction<ItemOf<GetFacetList
         dataService.facet.deleteFacets(ids, retrying).pipe(map(res => res.deleteFacets)),
 });
 
-export const assignFacetsToChannelBulkAction: BulkAction<
+export const assignFacetsToChannelBulkAction = createBulkAssignToChannelAction<
+    ItemOf<GetFacetListQuery, 'facets'>
+>({
+    location: 'facet-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.UpdateCatalog) ||
+        userPermissions.includes(Permission.UpdateFacet),
+    getItemName: item => item.name,
+    bulkAssignToChannel: (dataService, facetIds, channelId) =>
+        dataService.facet
+            .assignFacetsToChannel({
+                facetIds,
+                channelId,
+            })
+            .pipe(map(res => res.assignFacetsToChannel)),
+});
+
+export const removeFacetsFromChannelBulkAction = createBulkRemoveFromChannelAction<
     ItemOf<GetFacetListQuery, 'facets'>,
-    FacetListComponent
-> = {
+    RemoveFacetsFromChannelMutation['removeFacetsFromChannel'][number]
+>({
     location: 'facet-list',
-    label: _('catalog.assign-to-channel'),
-    icon: 'layers',
     requiresPermission: userPermissions =>
-        userPermissions.includes(Permission.UpdateFacet) ||
-        userPermissions.includes(Permission.UpdateCatalog),
-    isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-        const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
-        modalService
-            .fromComponent(AssignToChannelDialogComponent, {
-                size: 'md',
-                locals: {},
+        userPermissions.includes(Permission.DeleteCatalog) ||
+        userPermissions.includes(Permission.DeleteFacet),
+    getItemName: item => item.name,
+    bulkRemoveFromChannel: (dataService, facetIds, channelId, retrying) =>
+        dataService.facet
+            .removeFacetsFromChannel({
+                channelId: channelId,
+                facetIds,
+                force: retrying,
             })
-            .pipe(
-                switchMap(result => {
-                    if (result) {
-                        return dataService.facet
-                            .assignFacetsToChannel({
-                                facetIds: selection.map(f => f.id),
-                                channelId: result.id,
-                            })
-                            .pipe(mapTo(result));
-                    } else {
-                        return EMPTY;
-                    }
-                }),
-            )
-            .subscribe(result => {
-                notificationService.success(_('catalog.assign-facets-to-channel-success'), {
-                    count: selection.length,
-                    channelCode: result.code,
-                });
-                clearSelection();
-            });
-    },
-};
+            .pipe(map(res => res.removeFacetsFromChannel)),
+    isErrorResult: result => (result.__typename === 'FacetInUseError' ? result.message : undefined),
+});
 
-export const removeFacetsFromChannelBulkAction: BulkAction<
+export const removeFacetsFromChannelBulkAction2: BulkAction<
     ItemOf<GetFacetListQuery, 'facets'>,
     FacetListComponent
 > = {

+ 17 - 70
packages/admin-ui/src/lib/catalog/src/components/product-list/product-list-bulk-actions.ts

@@ -1,10 +1,9 @@
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BulkAction,
-    currentChannelIsNotDefault,
+    createBulkRemoveFromChannelAction,
     DataService,
     DeletionResult,
-    getChannelCodeFromUserStatus,
     GetProductListQuery,
     isMultiChannel,
     ItemOf,
@@ -13,8 +12,8 @@ import {
     Permission,
 } from '@vendure/admin-ui/core';
 import { unique } from '@vendure/common/lib/unique';
-import { EMPTY, from, of } from 'rxjs';
-import { mapTo, switchMap } from 'rxjs/operators';
+import { EMPTY } from 'rxjs';
+import { map, switchMap } from 'rxjs/operators';
 
 import { AssignProductsToChannelDialogComponent } from '../assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';
 import { BulkAddFacetValuesDialogComponent } from '../bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';
@@ -87,10 +86,8 @@ export const assignProductsToChannelBulkAction: BulkAction<
         userPermissions.includes(Permission.UpdateCatalog) ||
         userPermissions.includes(Permission.UpdateProduct),
     isVisible: ({ injector }) => isMultiChannel(injector.get(DataService)),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
+    onClick: ({ injector, selection, clearSelection }) => {
         const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
         modalService
             .fromComponent(AssignProductsToChannelDialogComponent, {
                 size: 'lg',
@@ -107,72 +104,22 @@ export const assignProductsToChannelBulkAction: BulkAction<
     },
 };
 
-export const removeProductsFromChannelBulkAction: BulkAction<
-    ItemOf<GetProductListQuery, 'products'>,
-    ProductListComponent
-> = {
+export const removeProductsFromChannelBulkAction = createBulkRemoveFromChannelAction<
+    ItemOf<GetProductListQuery, 'products'>
+>({
     location: 'product-list',
-    label: _('catalog.remove-from-channel'),
     requiresPermission: userPermissions =>
-        userPermissions.includes(Permission.UpdateChannel) ||
+        userPermissions.includes(Permission.UpdateCatalog) ||
         userPermissions.includes(Permission.UpdateProduct),
-    getTranslationVars: ({ injector }) => getChannelCodeFromUserStatus(injector.get(DataService)),
-    icon: 'layers',
-    iconClass: 'is-warning',
-    isVisible: ({ injector }) => currentChannelIsNotDefault(injector.get(DataService)),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-        const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
-        const activeChannelId$ = dataService.client
-            .userStatus()
-            .mapSingle(({ userStatus }) => userStatus.activeChannelId);
-
-        from(getChannelCodeFromUserStatus(injector.get(DataService)))
-            .pipe(
-                switchMap(({ channelCode }) =>
-                    modalService.dialog({
-                        title: _('catalog.remove-from-channel'),
-                        translationVars: {
-                            channelCode,
-                        },
-                        buttons: [
-                            { type: 'secondary', label: _('common.cancel') },
-                            {
-                                type: 'danger',
-                                label: _('common.remove'),
-                                returnValue: true,
-                            },
-                        ],
-                    }),
-                ),
-                switchMap(res =>
-                    res
-                        ? activeChannelId$.pipe(
-                              switchMap(activeChannelId =>
-                                  activeChannelId
-                                      ? dataService.product.removeProductsFromChannel({
-                                            channelId: activeChannelId,
-                                            productIds: selection.map(p => p.id),
-                                        })
-                                      : EMPTY,
-                              ),
-                              mapTo(true),
-                          )
-                        : of(false),
-                ),
-            )
-            .subscribe(removed => {
-                if (removed) {
-                    clearSelection();
-                    notificationService.success(_('common.notify-remove-products-from-channel-success'), {
-                        count: selection.length,
-                    });
-                    setTimeout(() => hostComponent.refresh(), 1000);
-                }
-            });
-    },
-};
+    getItemName: item => item.name,
+    bulkRemoveFromChannel: (dataService, productIds, channelId) =>
+        dataService.product
+            .removeProductsFromChannel({
+                channelId: channelId,
+                productIds,
+            })
+            .pipe(map(res => res.removeProductsFromChannel)),
+});
 
 export const assignFacetValuesToProductsBulkAction: BulkAction<
     ItemOf<GetProductListQuery, 'products'>,

+ 1 - 1
packages/admin-ui/src/lib/catalog/src/public_api.ts

@@ -6,7 +6,7 @@ export * from './components/asset-detail/asset-detail.component';
 export * from './components/asset-list/asset-list.component';
 export * from './components/assets/assets.component';
 export * from './components/assign-products-to-channel-dialog/assign-products-to-channel-dialog.component';
-export * from './components/assign-to-channel-dialog/assign-to-channel-dialog.component';
+export * from '../../core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component';
 export * from './components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.component';
 export * from './components/bulk-add-facet-values-dialog/bulk-add-facet-values-dialog.graphql';
 export * from './components/collection-contents/collection-contents.component';

+ 214 - 5
packages/admin-ui/src/lib/core/src/common/utilities/bulk-action-utils.ts

@@ -1,12 +1,14 @@
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
-import { lastValueFrom, Observable, of, switchMap } from 'rxjs';
-import { map } from 'rxjs/operators';
+import { unique } from '@vendure/common/lib/unique';
+import { EMPTY, from, lastValueFrom, Observable, of, switchMap } from 'rxjs';
+import { map, mapTo } from 'rxjs/operators';
 
 import { DataService } from '../../data/providers/data.service';
 import { BulkAction } from '../../providers/bulk-action-registry/bulk-action-types';
 import { ModalService } from '../../providers/modal/modal.service';
 import { NotificationService } from '../../providers/notification/notification.service';
+import { AssignToChannelDialogComponent } from '../../shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component';
 import { BaseListComponent } from '../base-list.component';
 import { DeletionResponse, DeletionResult } from '../generated-types';
 
@@ -86,7 +88,7 @@ export function createBulkDeleteAction<ItemType>(config: CreateBulkDeleteActionC
                 const nMore = items.length > 5 ? items.length - 5 : 0;
                 return modalService
                     .dialog({
-                        title: _('catalog.confirm-bulk-delete'),
+                        title: _('common.confirm-bulk-delete'),
                         body: message ? message : nMore ? _('common.list-items-and-n-more') : itemNames,
                         translationVars: { items: itemNames, nMore },
                         buttons: [
@@ -146,13 +148,13 @@ export function createBulkDeleteAction<ItemType>(config: CreateBulkDeleteActionC
                     if (deletedCount) {
                         hostComponent.refresh();
                         clearSelection();
-                        notificationService.success(_('catalog.notify-delete-success-with-count'), {
+                        notificationService.success(_('common.notify-delete-success-with-count'), {
                             count: deletedCount,
                         });
                     }
                     const notDeletedCount = selection.length - deletedCount;
                     if (0 < notDeletedCount && notDeletedCount < selection.length) {
-                        notificationService.error(_('catalog.notify-delete-error-with-count'), {
+                        notificationService.error(_('common.notify-delete-error-with-count'), {
                             count: notDeletedCount,
                         });
                     }
@@ -161,3 +163,210 @@ export function createBulkDeleteAction<ItemType>(config: CreateBulkDeleteActionC
     };
     return bulkDeleteAction;
 }
+
+export type CreateBulkAssignToChannelActionConfig<ItemType> = Pick<
+    BulkAction,
+    'location' | 'requiresPermission'
+> & {
+    getItemName: (item: ItemType) => string;
+    bulkAssignToChannel: (
+        dataService: DataService,
+        ids: string[],
+        channelId: string,
+    ) => Observable<Array<Partial<ItemType>>>;
+};
+
+export function createBulkAssignToChannelAction<ItemType>(
+    config: CreateBulkAssignToChannelActionConfig<ItemType>,
+) {
+    const bulkAssignToChannelAction: BulkAction<any, BaseListComponent<any, any>> = {
+        location: config.location,
+        label: _('common.assign-to-channel'),
+        icon: 'layers',
+        requiresPermission: config.requiresPermission,
+        onClick: ({ injector, selection, hostComponent, clearSelection }) => {
+            const modalService = injector.get(ModalService);
+            const dataService = injector.get(DataService);
+            const notificationService = injector.get(NotificationService);
+            const itemNames = selection
+                .slice(0, 5)
+                .map(c => config.getItemName(c))
+                .join(', ');
+            const nMore = selection.length > 5 ? selection.length - 5 : 0;
+            modalService
+                .fromComponent(AssignToChannelDialogComponent, {
+                    size: 'md',
+                    locals: {
+                        itemNames,
+                        nMore,
+                    },
+                })
+                .pipe(
+                    switchMap(result => {
+                        if (result) {
+                            return config
+                                .bulkAssignToChannel(
+                                    dataService,
+                                    selection.map(c => c.id),
+                                    result.id,
+                                )
+                                .pipe(mapTo(result));
+                        } else {
+                            return EMPTY;
+                        }
+                    }),
+                )
+                .subscribe(result => {
+                    notificationService.success(_('common.notify-assign-to-channel-success-with-count'), {
+                        count: selection.length,
+                        channelCode: result.code,
+                    });
+                    clearSelection();
+                });
+        },
+    };
+    return bulkAssignToChannelAction;
+}
+
+export type CreateBulkRemoveFromChannelActionConfig<ItemType, RemoveResult = Partial<ItemType>> = Pick<
+    BulkAction,
+    'location' | 'requiresPermission'
+> & {
+    getItemName: (item: ItemType) => string;
+    bulkRemoveFromChannel: (
+        dataService: DataService,
+        ids: string[],
+        channelId: string,
+        retrying: boolean,
+    ) => Observable<RemoveResult[]>;
+    /**
+     * An optional test of whether the removal succeeded for the given item. If this
+     * function returns a string, that is taken to be an error message which will be
+     * displayed to the user.
+     */
+    isErrorResult?: (result: RemoveResult) => string | undefined;
+};
+
+export function createBulkRemoveFromChannelAction<ItemType, ResultType = Partial<ItemType>>(
+    config: CreateBulkRemoveFromChannelActionConfig<ItemType, ResultType>,
+) {
+    const bulkRemoveFromChannelAction: BulkAction<any, BaseListComponent<any, any>> = {
+        location: config.location,
+        label: _('common.remove-from-channel'),
+        icon: 'layers',
+        iconClass: 'is-warning',
+        requiresPermission: config.requiresPermission,
+        onClick: ({ injector, selection, hostComponent, clearSelection }) => {
+            const modalService = injector.get(ModalService);
+            const dataService = injector.get(DataService);
+            const notificationService = injector.get(NotificationService);
+            const activeChannelId$ = dataService.client
+                .userStatus()
+                .mapSingle(({ userStatus }) => userStatus.activeChannelId);
+
+            function showModalAndDelete(items: ItemType[], message?: string) {
+                const itemNames = items
+                    .slice(0, 5)
+                    .map(c => config.getItemName(c))
+                    .join(', ');
+                const nMore = items.length > 5 ? items.length - 5 : 0;
+                return modalService
+                    .dialog({
+                        title: _('common.confirm-bulk-remove-from-channel'),
+                        body: message ? message : nMore ? _('common.list-items-and-n-more') : itemNames,
+                        translationVars: {
+                            count: selection.length,
+                            items: itemNames,
+                            nMore,
+                        },
+                        size: message ? 'lg' : 'md',
+                        buttons: [
+                            { type: 'secondary', label: _('common.cancel') },
+                            {
+                                type: 'danger',
+                                label: message ? _('common.force-remove') : _('common.remove'),
+                                returnValue: true,
+                            },
+                        ],
+                    })
+                    .pipe(
+                        switchMap(res =>
+                            res
+                                ? activeChannelId$.pipe(
+                                      switchMap(activeChannelId =>
+                                          activeChannelId
+                                              ? config.bulkRemoveFromChannel(
+                                                    dataService,
+                                                    selection.map(c => c.id),
+                                                    activeChannelId,
+                                                    message != null,
+                                                )
+                                              : EMPTY,
+                                      ),
+                                  )
+                                : EMPTY,
+                        ),
+                    );
+            }
+
+            showModalAndDelete(selection)
+                .pipe(
+                    switchMap(result => {
+                        let removedCount = selection.length;
+                        const errors: string[] = [];
+                        const errorIds: string[] = [];
+                        let i = 0;
+                        for (const item of result) {
+                            const errorMessage = config.isErrorResult
+                                ? config.isErrorResult(item)
+                                : undefined;
+                            if (errorMessage) {
+                                errors.push(errorMessage);
+                                errorIds.push(selection[i]?.id);
+                                removedCount--;
+                            }
+                            i++;
+                        }
+                        if (0 < errorIds.length) {
+                            const errorSelection = selection.filter(s => errorIds.includes(s.id));
+                            return showModalAndDelete(errorSelection, errors.join('\n')).pipe(
+                                map(result2 => {
+                                    const notRemovedCount = result2.filter(r => {
+                                        const secondTryErrorMessage = config.isErrorResult
+                                            ? config.isErrorResult(r)
+                                            : undefined;
+                                        return typeof secondTryErrorMessage === 'string';
+                                    }).length;
+                                    return selection.length - notRemovedCount;
+                                }),
+                            );
+                        } else {
+                            return of(removedCount);
+                        }
+                    }),
+                    switchMap(removedCount =>
+                        removedCount
+                            ? getChannelCodeFromUserStatus(dataService).then(({ channelCode }) => ({
+                                  channelCode,
+                                  removedCount,
+                              }))
+                            : EMPTY,
+                    ),
+                )
+                .subscribe(({ removedCount, channelCode }) => {
+                    if (removedCount) {
+                        hostComponent.refresh();
+                        clearSelection();
+                        notificationService.success(
+                            _('common.notify-remove-from-channel-success-with-count'),
+                            {
+                                count: removedCount,
+                                channelCode,
+                            },
+                        );
+                    }
+                });
+        },
+    };
+    return bulkRemoveFromChannelAction;
+}

+ 40 - 0
packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.html

@@ -0,0 +1,40 @@
+<ng-template vdrDialogTitle>
+    {{ 'common.confirm-bulk-assign-to-channel' | translate }}
+</ng-template>
+<div class="form-grid">
+    <vdr-form-item>
+        <div *ngIf="0 < nMore">
+            {{
+                'common.list-items-and-n-more'
+                    | translate
+                        : {
+                              items: itemNames,
+                              nMore: nMore
+                          }
+            }}
+        </div>
+        <div *ngIf="nMore === 0">
+            {{ itemNames }}
+        </div>
+    </vdr-form-item>
+    <vdr-form-field [label]="'common.channel' | translate" class="mb-4">
+        <vdr-channel-assignment-control
+            clrInput
+            [multiple]="false"
+            [includeDefaultChannel]="false"
+            [formControl]="selectedChannelIdControl"
+        ></vdr-channel-assignment-control>
+    </vdr-form-field>
+</div>
+
+<ng-template vdrDialogButtons>
+    <button type="button" class="btn" (click)="cancel()">{{ 'common.cancel' | translate }}</button>
+    <button type="submit" (click)="assign()" [disabled]="!selectedChannel" class="btn btn-primary">
+        <ng-template [ngIf]="selectedChannel" [ngIfElse]="noSelection">
+            {{ 'catalog.assign-to-named-channel' | translate : { channelCode: selectedChannel?.code } }}
+        </ng-template>
+        <ng-template #noSelection>
+            {{ 'catalog.no-channel-selected' | translate }}
+        </ng-template>
+    </button>
+</ng-template>

+ 0 - 0
packages/admin-ui/src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.scss → packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.scss


+ 2 - 1
packages/admin-ui/src/lib/catalog/src/components/assign-to-channel-dialog/assign-to-channel-dialog.component.ts → packages/admin-ui/src/lib/core/src/shared/components/assign-to-channel-dialog/assign-to-channel-dialog.component.ts

@@ -18,7 +18,8 @@ export class AssignToChannelDialogComponent implements OnInit, Dialog<Channel> {
     resolveWith: (result?: Channel) => void;
     selectedChannelIdControl = new UntypedFormControl();
 
-    // assigned by ModalService.fromComponent() call
+    itemNames: string;
+    nMore: number;
 
     constructor(private dataService: DataService, private notificationService: NotificationService) {}
 

+ 3 - 3
packages/admin-ui/src/lib/core/src/shared/components/simple-dialog/simple-dialog.component.html

@@ -3,9 +3,9 @@
 <ng-template vdrDialogButtons>
     <ng-container *ngFor="let button of buttons">
         <button
-            class="btn"
-            [class.btn-primary]="button.type === 'primary'"
-            [class.btn-danger]="button.type === 'danger'"
+            class="button ml-2"
+            [class.primary]="button.type === 'primary'"
+            [class.danger]="button.type === 'danger'"
             (click)="resolveWith(button.returnValue)"
         >
             {{ button.label | translate: (button.translationVars || {}) }}

+ 2 - 0
packages/admin-ui/src/lib/core/src/shared/shared.module.ts

@@ -30,6 +30,7 @@ import { AssetPreviewDialogComponent } from './components/asset-preview-dialog/a
 import { AssetPreviewLinksComponent } from './components/asset-preview-links/asset-preview-links.component';
 import { AssetPreviewComponent } from './components/asset-preview/asset-preview.component';
 import { AssetSearchInputComponent } from './components/asset-search-input/asset-search-input.component';
+import { AssignToChannelDialogComponent } from './components/assign-to-channel-dialog/assign-to-channel-dialog.component';
 import { BulkActionMenuComponent } from './components/bulk-action-menu/bulk-action-menu.component';
 import { ChannelAssignmentControlComponent } from './components/channel-assignment-control/channel-assignment-control.component';
 import { ChannelBadgeComponent } from './components/channel-badge/channel-badge.component';
@@ -306,6 +307,7 @@ const DECLARATIONS = [
     CardControlsDirective,
     ZoneSelectorComponent,
     ChartComponent,
+    AssignToChannelDialogComponent,
 ];
 
 const DYNAMIC_FORM_INPUTS = [

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Přidat hodnotu atributu",
     "add-facets": "Přidat atribut",
     "add-option": "Přidat možnost",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Produkt byl úspěšně přiřazen do \"{ channel }\"",
     "assign-products-to-channel": "Přiřadit produkty do kanálu",
     "assign-to-channel": "Přiřadit do kanálu",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Obsah kolekce",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Smazat {count} {count, plural, one {médium} few {média} other {médií}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Žádný kanál nevybrán",
     "no-featured-asset": "Žádné zvýrazněné médium",
     "no-selection": "Žádný výběr",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Produkt se nepovedlo odebrat z kanálu",
     "notify-remove-product-from-channel-success": "Produkt byl úspěšně odebrán z kanálu",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Přidat položku do seznamu",
     "add-note": "Přidat poznámku",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Dostupné jazyky",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Kód",
     "collapse-entries": "Schovat vstupy",
     "confirm": "Potvrdit",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Smazat poznámku?",
     "confirm-navigation": "Potvrdit navigaci",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Žádné výsledky",
     "not-applicable": "",
     "not-set": "Nenastaveno",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Vyskytla se chyba, nebylo vytvořeno: { entity }",
     "notify-create-success": "Vytvořeno: { entity }",
     "notify-delete-error": "Vyskytla se chyba, nebylo smazáno: { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Smazáno: { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Vyskytla se chyba, nebylo možné uložit změny",
     "notify-saved-changes": "Změny uloženy",
     "notify-update-error": "Vyskytla se chyba, nebylo aktualizováno: { entity }",
@@ -291,6 +291,7 @@
     "public": "Veřejné",
     "remember-me": "Zapamatovat",
     "remove": "Smazat",
+    "remove-from-channel": "",
     "remove-item-from-list": "Odebrat položku ze seznamu",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {výsledek} other {výsledků/y}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Facettenwert hinzufügen",
     "add-facets": "Facetten hinzufügen",
     "add-option": "Option hinzufügen",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Produkt erfolgreich an \"{ channel }\" zugewiesen",
     "assign-products-to-channel": "Produkte dem Kanal zuweisen",
     "assign-to-channel": "Zuweisung an Kanal",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Inhalt der Sammlung",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "{count} {count, plural, one {Asset} other {Assets}} löschen?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Kein Kanal ausgewählt",
     "no-featured-asset": "Kein \"Featured Asset\"",
     "no-selection": "Keine Auswahl",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Das Produkt konnte nicht aus dem Kanal entfernt werden",
     "notify-remove-product-from-channel-success": "Das Produkt wurde erfolgreich aus dem Kanal entfernt",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Artikel zur Wunschliste hinzufügen",
     "add-note": "Notiz hinzufügen",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Verfügbare Sprachen",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Code",
     "collapse-entries": "Einträge einklappen",
     "confirm": "Bestätigen",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Notiz löschen?",
     "confirm-navigation": "Navigation bestätigen",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Keine Ergebnisse",
     "not-applicable": "",
     "not-set": "Nicht festgelegt",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Ein Fehler ist aufgetreten, { entity } konnte nicht erstellt werden",
     "notify-create-success": "{ entity } erstellt",
     "notify-delete-error": "Ein Fehler ist aufgetreten, { entity } konnte nicht gelöscht werden",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "{ entity } gelöscht",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Ein Fehler ist aufgetreten, die Änderungen konnten nicht gespeichert werden",
     "notify-saved-changes": "Änderungen gespeichert",
     "notify-update-error": "Ein Fehler ist aufgetreten, { entity } konnte nicht aktualisiert werden",
@@ -291,6 +291,7 @@
     "public": "Öffentlich",
     "remember-me": "Logindaten merken",
     "remove": "Entfernen",
+    "remove-from-channel": "",
     "remove-item-from-list": "Artikel von Liste entfernen",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {Ergebnis} other {Ergebnisse}}",

+ 11 - 10
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Add facet value",
     "add-facets": "Add facets",
     "add-option": "Add option",
+    "add-stock-location": "Add stock location",
     "asset": "Asset",
     "asset-preview-links": "Asset preview links",
     "assets": "Assets",
-    "assign-collections-to-channel-success": "Successfully assigned {count, plural, one {1 collection} other {{count} collections}} to { channelCode }",
-    "assign-facets-to-channel-success": "Successfully assigned {count, plural, one {1 facet} other {{count} facets}} to { channelCode }",
     "assign-product-to-channel-success": "Successfully assigned {count, plural, one {1 product} other {{count} products}} to { channel }",
     "assign-products-to-channel": "Assign products to channel",
     "assign-to-channel": "Assign to channel",
@@ -75,8 +74,6 @@
     "collection": "Collection",
     "collection-contents": "Collection contents",
     "collections": "Collections",
-    "confirm-bulk-delete": "Delete multiple items?",
-    "confirm-bulk-delete-collections": "Delete {count} collections?",
     "confirm-bulk-delete-products": "Delete {count} products?",
     "confirm-cancel": "Cancel?",
     "confirm-delete-assets": "Delete {count} {count, plural, one {asset} other {assets}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "No channel selected",
     "no-featured-asset": "No featured asset",
     "no-selection": "No selection",
-    "notify-bulk-delete-collections-success": "Successfully deleted {count, plural, one {1 collection} other {{count} collections}}",
     "notify-bulk-delete-products-success": "Successfully deleted {count, plural, one {1 product} other {{count} products}}",
-    "notify-delete-error-with-count": "Could not delete {count, plural, one {1 item} other {{count} items}}",
-    "notify-delete-success-with-count": "Successfully deleted {count, plural, one {1 item} other {{count} items}}",
-    "notify-remove-collections-from-channel-success": "Successfully removed {count, plural, one {1 collection} other {{count} collections}} from { channelCode }",
     "notify-remove-facets-from-channel-success": "Successfully removed {count, plural, one {1 facet} other {{count} facets}} from { channelCode }",
     "notify-remove-product-from-channel-error": "Could not remove product from channel",
     "notify-remove-product-from-channel-success": "Successfully removed product from channel",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Add item to list",
     "add-note": "Add note",
     "apply": "Apply",
+    "assign-to-channel": "Assign to channel",
     "available-languages": "Available languages",
     "boolean-and": "and",
     "boolean-false": "false",
@@ -213,6 +207,9 @@
     "code": "Code",
     "collapse-entries": "Collapse entries",
     "confirm": "Confirm",
+    "confirm-bulk-assign-to-channel": "Assign items to channel?",
+    "confirm-bulk-delete": "Delete the selected items?",
+    "confirm-bulk-remove-from-channel": "Remove items from current channel?",
     "confirm-delete-note": "Delete note?",
     "confirm-navigation": "Confirm navigation",
     "contents": "Contents",
@@ -263,12 +260,15 @@
     "no-results": "No results",
     "not-applicable": "Not applicable",
     "not-set": "Not set",
+    "notify-assign-to-channel-success-with-count": "Successfully assigned {count, plural, one {1 item} other {{count} items}} to { channelCode }",
     "notify-bulk-update-success": "Updated { count } { entity }",
     "notify-create-error": "An error occurred, could not create { entity }",
     "notify-create-success": "Created new { entity }",
     "notify-delete-error": "An error occurred, could not delete { entity }",
+    "notify-delete-error-with-count": "Could not delete {count, plural, one {1 item} other {{count} items}}",
     "notify-delete-success": "Deleted { entity }",
-    "notify-remove-products-from-channel-success": "Successfully removed { count } products from channel",
+    "notify-delete-success-with-count": "Successfully deleted {count, plural, one {1 item} other {{count} items}}",
+    "notify-remove-from-channel-success-with-count": "Successfully removed { count } items from channel",
     "notify-save-changes-error": "An error occurred, could not save changes",
     "notify-saved-changes": "Saved changes",
     "notify-update-error": "An error occurred, could not update { entity }",
@@ -291,6 +291,7 @@
     "public": "Public",
     "remember-me": "Remember me",
     "remove": "Remove",
+    "remove-from-channel": "Remove from current channel",
     "remove-item-from-list": "Remove item from list",
     "reset-columns": "Reset columns",
     "results-count": "{ count } {count, plural, one {result} other {results}}",
@@ -755,4 +756,4 @@
     "job-result": "Job result",
     "job-state": "Job state"
   }
-}
+}

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Añadir valor de faceta",
     "add-facets": "Añadir facetas",
     "add-option": "Añadir opción",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Producto asignado a \"{ channel }\" con éxito",
     "assign-products-to-channel": "Asignar productos a canal de ventas",
     "assign-to-channel": "Asignar a canal de ventas",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Contenidos de la colección",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "¿Eliminar recurso?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Ninún canal seleccionado",
     "no-featured-asset": "Sin recurso destacado",
     "no-selection": "Sin selección",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "No fue posible eliminar el producto del canal",
     "notify-remove-product-from-channel-success": "Producto eliminado del canal con éxito",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Añadir artículo a la lista",
     "add-note": "Añadir nota",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Idiomas disponibles",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Código",
     "collapse-entries": "Ocultar entradas",
     "confirm": "Confirmar",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "¿Eliminar nota?",
     "confirm-navigation": "Confirmar navegación",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Sin resultados",
     "not-applicable": "",
     "not-set": "Sin fijar",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Ha ocurrido un problema, imposible de crear { entity }",
     "notify-create-success": "Creado nuevo { entity }",
     "notify-delete-error": "Ha ocurrido un problema, imposible de eliminar { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Eliminado { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Ha ocurrido un problema, imposible de guardar cambios",
     "notify-saved-changes": "Cambios guardados",
     "notify-update-error": "Ha ocurrido un problema, imposible de actualizar{ entity }",
@@ -291,6 +291,7 @@
     "public": "Público",
     "remember-me": "Recordarme",
     "remove": "Borrar",
+    "remove-from-channel": "",
     "remove-item-from-list": "Eliminar elemento de la lista",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {resultado} other {resultados}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Ajout valeur du composant",
     "add-facets": "Ajout composant",
     "add-option": "Ajout option",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "produit attribué au canal \"{ channel }\"",
     "assign-products-to-channel": "Attribuer les produits au canal",
     "assign-to-channel": "Attribuer au canal",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Contenu de la Collection",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Supprimer {count} {count, plural, one {fichier} other {fichiers}} ?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Pas de canal sélectionné",
     "no-featured-asset": "Pas de fichier vedette",
     "no-selection": "Pas de sélection",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Retrait du produit du canal échoué",
     "notify-remove-product-from-channel-success": "Retrait du produit du canal réussi",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Ajouter un article à la liste",
     "add-note": "Ajouter une note",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Langues disponibles",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Code",
     "collapse-entries": "Réduire les éléments",
     "confirm": "Confirmer",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Supprimer la note ?",
     "confirm-navigation": "Confirmer la navigation",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Aucun resultat",
     "not-applicable": "",
     "not-set": "Non défini",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Une erreur est survenue, création de { entity } échouée",
     "notify-create-success": "Nouveau { entity } créé",
     "notify-delete-error": "Une erreur est survenue, suppression de { entity } échouée",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "{ entity } supprimé",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Une erreur est survenue, Changements non enregistrés",
     "notify-saved-changes": "Changements enregistrés",
     "notify-update-error": "Une erreur est survenue, mise à jour de { entity } échouée",
@@ -291,6 +291,7 @@
     "public": "Public",
     "remember-me": "Se souvenir de moi",
     "remove": "Retirer",
+    "remove-from-channel": "",
     "remove-item-from-list": "Retirer l'article de la liste",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {resultat} other {resultats}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Aggiungi valore attributo",
     "add-facets": "Aggiungi attributi",
     "add-option": "Aggiungi opzione",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Prodotto assegnato correttamente a \"{ channel }\"",
     "assign-products-to-channel": "Assegna prodotto al canale",
     "assign-to-channel": "Assegna a un canale",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Contenuti della Collezione",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Eliminare {count} {count, plural, one {media} other {media}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Nessun canale selezionato",
     "no-featured-asset": "Nessun media in evidenza",
     "no-selection": "Nessuna selezione",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Impossibile rimuovere il prodotto dal canale",
     "notify-remove-product-from-channel-success": "Prodotto rimosso dal canale",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Aggiungi elemento alla lista",
     "add-note": "Aggiungi nota",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Lingue disponibili",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Codice",
     "collapse-entries": "Riduci elementi",
     "confirm": "Conferma",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Cancellare la nota?",
     "confirm-navigation": "Prosegui con la navigazione",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Nessun risultato",
     "not-applicable": "",
     "not-set": "Non impostato",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Si è verificato un errore, impossibile creare { entity }",
     "notify-create-success": "Creato nuovo { entity }",
     "notify-delete-error": "Si è verificato un errore, impossibile cancellare { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Cancellato { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Si è verificato un errore, impossibile salvare le modifiche",
     "notify-saved-changes": "Modifiche salvate",
     "notify-update-error": "Si è verificato un errore, impossibile aggiornare { entity }",
@@ -291,6 +291,7 @@
     "public": "Pubblico",
     "remember-me": "Ricordami",
     "remove": "Rimuovi",
+    "remove-from-channel": "",
     "remove-item-from-list": "Rimuovi elemento dalla lista",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {risultato} other {risultati}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Dodaj nazwe faseta",
     "add-facets": "Dodaj faset",
     "add-option": "Dodaj opcje",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Pomyślnie przypisano produkt do \"{ channel }\"",
     "assign-products-to-channel": "Przypisz produkt do kanału",
     "assign-to-channel": "Przypisz do kanału",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Zawartość kolekcji",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Brak zaznaczonego kanału",
     "no-featured-asset": "Brak polecanego zasobu",
     "no-selection": "Brak zaznaczenia",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Błąd usuwania produktu z kanału",
     "notify-remove-product-from-channel-success": "Produkt pomyślnie usunięty z kanału",
@@ -197,6 +190,7 @@
     "add-item-to-list": "",
     "add-note": "",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Dostępne języki",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Kod",
     "collapse-entries": "",
     "confirm": "",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "",
     "confirm-navigation": "Potwierdź nawigacje",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Brak wyników",
     "not-applicable": "",
     "not-set": "Nie ustawione",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Wystąpił błąd, nie można utworzyć { entity }",
     "notify-create-success": "Utworzono { entity }",
     "notify-delete-error": "Wystąpił błąd, nie można usunąć { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Usunięto { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Wystąpił błąd, nie można zapisać zmian",
     "notify-saved-changes": "Zapisano zmiany",
     "notify-update-error": "Wystąpił błąd, nie można zaktualizować { entity }",
@@ -291,6 +291,7 @@
     "public": "Publiczne",
     "remember-me": "Zapamiętaj mnie",
     "remove": "Usuń",
+    "remove-from-channel": "",
     "remove-item-from-list": "",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {wynik} other {wyników}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Adiciona valor para etiqueta",
     "add-facets": "Adiciona etiqueta",
     "add-option": "Adiciona opção",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Produto atribuído com sucesso a \"{ channel }\"",
     "assign-products-to-channel": "Atribuir produtos ao canal",
     "assign-to-channel": "Atribuir ao canal",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Conteúdo da categoria",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Excluir {count} {count, plural, one {asset} other {assets}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Nenhum canal selecionado",
     "no-featured-asset": "Nenhum recurso em destaque",
     "no-selection": "Nenhuma seleção",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Não foi possível remover o produto do canal",
     "notify-remove-product-from-channel-success": "Produto removido com sucesso do canal",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Adicionar item à lista",
     "add-note": "Adicionar nota",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Idiomas disponíveis",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Código",
     "collapse-entries": "Recolher entradas",
     "confirm": "Confirme",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Excluir nota?",
     "confirm-navigation": "Confrme navegação",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Sem resultados",
     "not-applicable": "",
     "not-set": "Não configurado",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Ocorreu um erro, não foi possível criar { entity }",
     "notify-create-success": "Criado novo { entity }",
     "notify-delete-error": "Ocorreu um erro, não foi possível excluir { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Excluído { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Ocorreu um erro, não foi possível salvar as alterações",
     "notify-saved-changes": "Alterações salvas",
     "notify-update-error": "Ocorreu um erro, não foi possível atualizar { entity }",
@@ -291,6 +291,7 @@
     "public": "Público",
     "remember-me": "Lembre de mim",
     "remove": "Exclui",
+    "remove-from-channel": "",
     "remove-item-from-list": "",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {result} other {results}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Adicionar novo valor",
     "add-facets": "Adicionar etiqueta",
     "add-option": "Adicionar opção",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Produto atribuído com sucesso a \"{ channel }\"",
     "assign-products-to-channel": "Atribuir produtos ao canal",
     "assign-to-channel": "Atribuir ao canal",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Conteúdo da categoria",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Eliminar {count} {count, plural, one {imagem} other {imagens}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Nenhum canal seleccionado",
     "no-featured-asset": "Nenhum recurso em destaque",
     "no-selection": "Nenhuma imagem seleccionada",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Não foi possível remover o produto do canal",
     "notify-remove-product-from-channel-success": "Produto removido do canal com sucesso",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Adicionar item à lista",
     "add-note": "Adicionar nota",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Idiomas disponíveis",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Código",
     "collapse-entries": "Recolher entradas",
     "confirm": "Confirmar",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Eliminar nota?",
     "confirm-navigation": "Descartar modificações?",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Nenhum resultado encontrado",
     "not-applicable": "",
     "not-set": "Não configurado",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Ocorreu um erro. Não foi possível criar { entity }",
     "notify-create-success": "Novo(a) { entity } adicionado(a)",
     "notify-delete-error": "Ocorreu um erro, não foi possível eliminar { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "{ entity } excluído(a)",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Ocorreu um erro. Não foi possível guardar as alterações",
     "notify-saved-changes": "Alterações guardadas",
     "notify-update-error": "Ocorreu um erro. Não foi possível actualizar a entidade { entity }",
@@ -291,6 +291,7 @@
     "public": "Público",
     "remember-me": "Lembre-se de mim",
     "remove": "Eliminar",
+    "remove-from-channel": "",
     "remove-item-from-list": "Remover item da lista",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {resultado} other {resultados}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Добавить значение тега",
     "add-facets": "Добавить тег",
     "add-option": "Добавить опции",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Товар успешно добавлен в канал \"{ channel }\"",
     "assign-products-to-channel": "Добавить товары в канал",
     "assign-to-channel": "Добавить в канал",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Содержание коллекции",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Удалить {count} {count, plural, one {медиа-объект} other {медиа-объектов}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Канал не выбран",
     "no-featured-asset": "Нет избранного медиа-объекта",
     "no-selection": "Не выбрано",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Не удалось удалить товар из канала",
     "notify-remove-product-from-channel-success": "Товар успешно удален из канала",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Добавить позицию в список",
     "add-note": "Добавить заметку",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Доступные языки",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Код",
     "collapse-entries": "Свернуть записи",
     "confirm": "Подтверждать",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Удалить заметку?",
     "confirm-navigation": "Подтвердите навигацию",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Нет результатов",
     "not-applicable": "",
     "not-set": "Не задано",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Ошибка, не удалось создать { entity }",
     "notify-create-success": "Создано новое { entity }",
     "notify-delete-error": "Ошибка, не удалось удалить { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Удалено { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Произошла ошибка, не удалось сохранить изменения",
     "notify-saved-changes": "Сохранены изменения",
     "notify-update-error": "Произошла ошибка, не удалось обновить { entity }",
@@ -291,6 +291,7 @@
     "public": "Публичная",
     "remember-me": "Запомнить меня",
     "remove": "Удалить",
+    "remove-from-channel": "",
     "remove-item-from-list": "Удалить позицию из списка",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {результат} other {результатов}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -58,11 +58,10 @@
     "add-facet-value": "Додати значення тегу",
     "add-facets": "Додати тег",
     "add-option": "Додати опцію",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "Товар успішно доданий в канал \"{ channel }\"",
     "assign-products-to-channel": "Додати товари в канал",
     "assign-to-channel": "Додати в канал",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "Зміст колекції",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "Видалити {count} {count, plural, one {медіа-об'єкт} other {медіа-об'єктів}}?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "Канал не вибрано",
     "no-featured-asset": "Немає обраного медіа-об'єкта",
     "no-selection": "Не вибрано",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Не вдалося видалити товар з каналу",
     "notify-remove-product-from-channel-success": "Товар успішно видалений з каналу",
@@ -197,6 +190,7 @@
     "add-item-to-list": "Додати позицію в список",
     "add-note": "Додати замітку",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "Доступні мови",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "Код",
     "collapse-entries": "Згорнути записи",
     "confirm": "Підтверджувати",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "Видалити замітку?",
     "confirm-navigation": "Підтвердіть навігацію",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "Немає результатів",
     "not-applicable": "",
     "not-set": "Не задано",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "Помилка, не вдалося створити { entity }",
     "notify-create-success": "Створено нове { entity }",
     "notify-delete-error": "Помилка, не вдалося видалити { entity }",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "Видалено { entity }",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "Сталася помилка, не вдалося зберегти зміни",
     "notify-saved-changes": "Збережені зміни",
     "notify-update-error": "Сталася помилка, не вдалося оновити { entity }",
@@ -291,6 +291,7 @@
     "public": "Публічна",
     "remember-me": "Запам'ятати мене",
     "remove": "Видалити",
+    "remove-from-channel": "",
     "remove-item-from-list": "Видалити позицію зі списку",
     "reset-columns": "",
     "results-count": "{ count } {count, plural, one {результат} other {результатів}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -58,11 +58,10 @@
     "add-facet-value": "添加特征值",
     "add-facets": "添加特征",
     "add-option": "添加规格组",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "成功将产品添加至销售渠道\"{ channel }\"",
     "assign-products-to-channel": "分配产品到销售渠道",
     "assign-to-channel": "分配至销售渠道",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "系列产品",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "确认删除{count}个资源吗?",
@@ -121,11 +118,7 @@
     "no-channel-selected": "未选择销售渠道",
     "no-featured-asset": "无特征图片",
     "no-selection": "尚未选择",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "从渠道中移除商品失败",
     "notify-remove-product-from-channel-success": "成功从渠道中移除商品",
@@ -197,6 +190,7 @@
     "add-item-to-list": "添加到列表",
     "add-note": "添加注释",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "可用语言",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "编码",
     "collapse-entries": "收起",
     "confirm": "确认",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "删除笔记",
     "confirm-navigation": "导航确认",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "没找到任何结果",
     "not-applicable": "",
     "not-set": "未设置",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "添加{ entity }失败",
     "notify-create-success": "{ entity }已添加",
     "notify-delete-error": "删除{ entity }失败",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "{ entity }已删除",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "保存失败",
     "notify-saved-changes": "修改已保存",
     "notify-update-error": "更新{ entity }失败",
@@ -291,6 +291,7 @@
     "public": "公开",
     "remember-me": "记住我",
     "remove": "删除",
+    "remove-from-channel": "",
     "remove-item-from-list": "从列表中移除",
     "reset-columns": "",
     "results-count": "{count, plural, =0{无} other {{count}个过滤结果}}",

+ 10 - 9
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -58,11 +58,10 @@
     "add-facet-value": "新增特徵值",
     "add-facets": "新增特徵",
     "add-option": "新增規格選項",
+    "add-stock-location": "",
     "asset": "",
     "asset-preview-links": "",
     "assets": "",
-    "assign-collections-to-channel-success": "",
-    "assign-facets-to-channel-success": "",
     "assign-product-to-channel-success": "成功將產品新增至渠道\"{ channel }\"",
     "assign-products-to-channel": "分配產品到渠道",
     "assign-to-channel": "分配至渠道",
@@ -75,8 +74,6 @@
     "collection": "",
     "collection-contents": "系列產品",
     "collections": "",
-    "confirm-bulk-delete": "",
-    "confirm-bulk-delete-collections": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-assets": "",
@@ -121,11 +118,7 @@
     "no-channel-selected": "並未選擇渠道",
     "no-featured-asset": "並無特徵圖片",
     "no-selection": "尚未選擇",
-    "notify-bulk-delete-collections-success": "",
     "notify-bulk-delete-products-success": "",
-    "notify-delete-error-with-count": "",
-    "notify-delete-success-with-count": "",
-    "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "從渠道中移除商品失敗",
     "notify-remove-product-from-channel-success": "成功從渠道中移除商品",
@@ -197,6 +190,7 @@
     "add-item-to-list": "",
     "add-note": "",
     "apply": "",
+    "assign-to-channel": "",
     "available-languages": "可用語言",
     "boolean-and": "",
     "boolean-false": "",
@@ -213,6 +207,9 @@
     "code": "編碼",
     "collapse-entries": "",
     "confirm": "",
+    "confirm-bulk-assign-to-channel": "",
+    "confirm-bulk-delete": "",
+    "confirm-bulk-remove-from-channel": "",
     "confirm-delete-note": "",
     "confirm-navigation": "導航確認",
     "contents": "",
@@ -263,12 +260,15 @@
     "no-results": "没找到任何結果",
     "not-applicable": "",
     "not-set": "未設定",
+    "notify-assign-to-channel-success-with-count": "",
     "notify-bulk-update-success": "",
     "notify-create-error": "新增{ entity }失敗",
     "notify-create-success": "{ entity }已新增",
     "notify-delete-error": "移除{ entity }失敗",
+    "notify-delete-error-with-count": "",
     "notify-delete-success": "{ entity }已移除",
-    "notify-remove-products-from-channel-success": "",
+    "notify-delete-success-with-count": "",
+    "notify-remove-from-channel-success-with-count": "",
     "notify-save-changes-error": "保存失敗",
     "notify-saved-changes": "修改已保存",
     "notify-update-error": "更新{ entity }失敗",
@@ -291,6 +291,7 @@
     "public": "公開",
     "remember-me": "記住登入帳號",
     "remove": "移除",
+    "remove-from-channel": "",
     "remove-item-from-list": "",
     "reset-columns": "",
     "results-count": "{count, plural, =0{無} other {{count}個篩選結果}}",

+ 12 - 0
packages/admin-ui/src/lib/static/styles/global/_buttons.scss

@@ -39,6 +39,18 @@
             }
         }
     }
+
+    &.danger,
+    &.btn-danger {
+        &:not(:disabled) {
+            background-color: var(--color-error-700);
+            color: white;
+            &:hover {
+                background-color: var(--color-error-800);
+                color: white;
+            }
+        }
+    }
 }
 
 .button-ghost {