فهرست منبع

feat(admin-ui): Implement bulk delete for all regular lists

Michael Bromley 2 سال پیش
والد
کامیت
ad1a82c199
63فایلهای تغییر یافته به همراه866 افزوده شده و 655 حذف شده
  1. 36 36
      packages/admin-ui/i18n-coverage.json
  2. 1 0
      packages/admin-ui/src/lib/catalog/src/catalog.module.ts
  3. 7 80
      packages/admin-ui/src/lib/catalog/src/components/facet-list/facet-list-bulk-actions.ts
  4. 155 0
      packages/admin-ui/src/lib/core/src/common/generated-types.ts
  5. 118 1
      packages/admin-ui/src/lib/core/src/common/utilities/bulk-action-utils.ts
  6. 1 0
      packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.html
  7. 8 0
      packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.ts
  8. 18 0
      packages/admin-ui/src/lib/core/src/data/definitions/administrator-definitions.ts
  9. 9 0
      packages/admin-ui/src/lib/core/src/data/definitions/customer-definitions.ts
  10. 9 0
      packages/admin-ui/src/lib/core/src/data/definitions/promotion-definitions.ts
  11. 54 0
      packages/admin-ui/src/lib/core/src/data/definitions/settings-definitions.ts
  12. 9 0
      packages/admin-ui/src/lib/core/src/data/definitions/shipping-definitions.ts
  13. 18 0
      packages/admin-ui/src/lib/core/src/data/providers/administrator-data.service.ts
  14. 8 0
      packages/admin-ui/src/lib/core/src/data/providers/customer-data.service.ts
  15. 8 0
      packages/admin-ui/src/lib/core/src/data/providers/promotion-data.service.ts
  16. 62 1
      packages/admin-ui/src/lib/core/src/data/providers/settings-data.service.ts
  17. 10 0
      packages/admin-ui/src/lib/core/src/data/providers/shipping-method-data.service.ts
  18. 15 1
      packages/admin-ui/src/lib/core/src/providers/bulk-action-registry/bulk-action-types.ts
  19. 0 1
      packages/admin-ui/src/lib/core/src/shared/components/data-table-2/data-table2.component.scss
  20. 4 0
      packages/admin-ui/src/lib/core/src/shared/components/language-selector/language-selector.component.scss
  21. 10 0
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list-bulk-actions.ts
  22. 1 1
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.html
  23. 1 33
      packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts
  24. 7 2
      packages/admin-ui/src/lib/customer/src/customer.module.ts
  25. 12 0
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list-bulk-actions.ts
  26. 1 1
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.html
  27. 2 39
      packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts
  28. 7 2
      packages/admin-ui/src/lib/marketing/src/marketing.module.ts
  29. 13 8
      packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.html
  30. 12 0
      packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list-bulk-actions.ts
  31. 17 0
      packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list-bulk-actions.ts
  32. 1 33
      packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts
  33. 12 0
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list-bulk-actions.ts
  34. 1 0
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.html
  35. 3 42
      packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts
  36. 20 0
      packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list-bulk-actions.ts
  37. 6 45
      packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.html
  38. 15 82
      packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.ts
  39. 10 0
      packages/admin-ui/src/lib/settings/src/components/role-list/role-list-bulk-actions.ts
  40. 1 32
      packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts
  41. 10 0
      packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list-bulk-actions.ts
  42. 1 32
      packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts
  43. 18 0
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list-bulk-actions.ts
  44. 3 2
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.html
  45. 4 40
      packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts
  46. 15 0
      packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list-bulk-actions.ts
  47. 1 44
      packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts
  48. 12 0
      packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list-bulk-actions.ts
  49. 1 43
      packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts
  50. 21 2
      packages/admin-ui/src/lib/settings/src/settings.module.ts
  51. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  52. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  53. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  54. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  55. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  56. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  57. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  58. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  59. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  60. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  61. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  62. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  63. 6 4
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

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

@@ -1,71 +1,71 @@
 {
-  "generatedOn": "2023-04-28T12:40:43.278Z",
-  "lastCommit": "f29aae9781b79ffa3c257d93639b844bf32fe6fa",
+  "generatedOn": "2023-05-01T20:16:42.501Z",
+  "lastCommit": "58dce8e9c84ba5e9050ad8aaed0c66bc256ad2d7",
   "translationStatus": {
     "cs": {
-      "tokenCount": 710,
-      "translatedCount": 584,
+      "tokenCount": 712,
+      "translatedCount": 581,
       "percentage": 82
     },
     "de": {
-      "tokenCount": 710,
-      "translatedCount": 567,
-      "percentage": 80
+      "tokenCount": 712,
+      "translatedCount": 564,
+      "percentage": 79
     },
     "en": {
-      "tokenCount": 710,
-      "translatedCount": 702,
+      "tokenCount": 712,
+      "translatedCount": 707,
       "percentage": 99
     },
     "es": {
-      "tokenCount": 710,
-      "translatedCount": 613,
+      "tokenCount": 712,
+      "translatedCount": 610,
       "percentage": 86
     },
     "fr": {
-      "tokenCount": 710,
-      "translatedCount": 605,
+      "tokenCount": 712,
+      "translatedCount": 602,
       "percentage": 85
     },
     "it": {
-      "tokenCount": 710,
-      "translatedCount": 611,
-      "percentage": 86
+      "tokenCount": 712,
+      "translatedCount": 608,
+      "percentage": 85
     },
     "pl": {
-      "tokenCount": 710,
-      "translatedCount": 407,
+      "tokenCount": 712,
+      "translatedCount": 404,
       "percentage": 57
     },
     "pt_BR": {
-      "tokenCount": 710,
-      "translatedCount": 582,
-      "percentage": 82
+      "tokenCount": 712,
+      "translatedCount": 579,
+      "percentage": 81
     },
     "pt_PT": {
-      "tokenCount": 710,
-      "translatedCount": 624,
-      "percentage": 88
+      "tokenCount": 712,
+      "translatedCount": 621,
+      "percentage": 87
     },
     "ru": {
-      "tokenCount": 710,
-      "translatedCount": 610,
-      "percentage": 86
+      "tokenCount": 712,
+      "translatedCount": 607,
+      "percentage": 85
     },
     "uk": {
-      "tokenCount": 710,
-      "translatedCount": 610,
-      "percentage": 86
+      "tokenCount": 712,
+      "translatedCount": 607,
+      "percentage": 85
     },
     "zh_Hans": {
-      "tokenCount": 710,
-      "translatedCount": 552,
-      "percentage": 78
+      "tokenCount": 712,
+      "translatedCount": 549,
+      "percentage": 77
     },
     "zh_Hant": {
-      "tokenCount": 710,
-      "translatedCount": 387,
-      "percentage": 55
+      "tokenCount": 712,
+      "translatedCount": 384,
+      "percentage": 54
     }
   }
 }

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

@@ -1,6 +1,7 @@
 import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
 import { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';
+import { deleteCustomersBulkAction } from '../../customer/src/components/customer-list/customer-list-bulk-actions';
 
 import { catalogRoutes } from './catalog.routes';
 import { ApplyFacetDialogComponent } from './components/apply-facet-dialog/apply-facet-dialog.component';

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

@@ -1,9 +1,9 @@
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BulkAction,
+    createBulkDeleteAction,
     currentChannelIsNotDefault,
     DataService,
-    DeletionResult,
     getChannelCodeFromUserStatus,
     GetFacetListQuery,
     isMultiChannel,
@@ -20,89 +20,16 @@ import { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assi
 
 import { FacetListComponent } from './facet-list.component';
 
-export const deleteFacetsBulkAction: BulkAction<ItemOf<GetFacetListQuery, 'facets'>, FacetListComponent> = {
+export const deleteFacetsBulkAction = createBulkDeleteAction<ItemOf<GetFacetListQuery, 'facets'>>({
     location: 'facet-list',
-    label: _('common.delete'),
-    icon: 'trash',
-    iconClass: 'is-danger',
     requiresPermission: userPermissions =>
         userPermissions.includes(Permission.DeleteFacet) ||
         userPermissions.includes(Permission.DeleteCatalog),
-    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
-        const modalService = injector.get(ModalService);
-        const dataService = injector.get(DataService);
-        const notificationService = injector.get(NotificationService);
-
-        function showModalAndDelete(facetIds: string[], message?: string) {
-            return modalService
-                .dialog({
-                    title: _('catalog.confirm-bulk-delete-facets'),
-                    translationVars: {
-                        count: selection.length,
-                    },
-                    size: message ? 'lg' : 'md',
-                    body: message,
-                    buttons: [
-                        { type: 'secondary', label: _('common.cancel') },
-                        {
-                            type: 'danger',
-                            label: message ? _('common.force-delete') : _('common.delete'),
-                            returnValue: true,
-                        },
-                    ],
-                })
-                .pipe(
-                    switchMap(res =>
-                        res
-                            ? dataService.facet
-                                  .deleteFacets(facetIds, !!message)
-                                  .pipe(map(res2 => res2.deleteFacets))
-                            : of([]),
-                    ),
-                );
-        }
-
-        showModalAndDelete(unique(selection.map(f => f.id)))
-            .pipe(
-                switchMap(result => {
-                    let deletedCount = 0;
-                    const errors: string[] = [];
-                    const errorIds: string[] = [];
-                    let i = 0;
-                    for (const item of result) {
-                        if (item.result === DeletionResult.DELETED) {
-                            deletedCount++;
-                        } else if (item.message) {
-                            errors.push(item.message);
-                            errorIds.push(selection[i]?.id);
-                        }
-                        i++;
-                    }
-                    if (0 < errorIds.length) {
-                        return showModalAndDelete(errorIds, errors.join('\n')).pipe(
-                            map(result2 => {
-                                const deletedCount2 = result2.filter(
-                                    r => r.result === DeletionResult.DELETED,
-                                ).length;
-                                return deletedCount + deletedCount2;
-                            }),
-                        );
-                    } else {
-                        return of(deletedCount);
-                    }
-                }),
-            )
-            .subscribe(deletedCount => {
-                if (deletedCount) {
-                    hostComponent.refresh();
-                    clearSelection();
-                    notificationService.success(_('catalog.notify-bulk-delete-facets-success'), {
-                        count: deletedCount,
-                    });
-                }
-            });
-    },
-};
+    getItemName: item => item.name,
+    shouldRetryItem: (response, item) => !!response.message,
+    bulkDelete: (dataService, ids, retrying) =>
+        dataService.facet.deleteFacets(ids, retrying).pipe(map(res => res.deleteFacets)),
+});
 
 export const assignFacetsToChannelBulkAction: BulkAction<
     ItemOf<GetFacetListQuery, 'facets'>,

+ 155 - 0
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -2592,16 +2592,22 @@ export type Mutation = {
   createZone: Zone;
   /** Delete an Administrator */
   deleteAdministrator: DeletionResponse;
+  /** Delete multiple Administrators */
+  deleteAdministrators: Array<DeletionResponse>;
   /** Delete an Asset */
   deleteAsset: DeletionResponse;
   /** Delete multiple Assets */
   deleteAssets: DeletionResponse;
   /** Delete a Channel */
   deleteChannel: DeletionResponse;
+  /** Delete multiple Channels */
+  deleteChannels: Array<DeletionResponse>;
   /** Delete a Collection and all of its descendants */
   deleteCollection: DeletionResponse;
   /** Delete multiple Collections and all of their descendants */
   deleteCollections: Array<DeletionResponse>;
+  /** Delete multiple Countries */
+  deleteCountries: Array<DeletionResponse>;
   /** Delete a Country */
   deleteCountry: DeletionResponse;
   /** Delete a Customer */
@@ -2611,6 +2617,8 @@ export type Mutation = {
   /** Delete a CustomerGroup */
   deleteCustomerGroup: DeletionResponse;
   deleteCustomerNote: DeletionResponse;
+  /** Deletes Customers */
+  deleteCustomers: Array<DeletionResponse>;
   /** Deletes a draft Order */
   deleteDraftOrder: DeletionResponse;
   /** Delete an existing Facet */
@@ -2622,6 +2630,8 @@ export type Mutation = {
   deleteOrderNote: DeletionResponse;
   /** Delete a PaymentMethod */
   deletePaymentMethod: DeletionResponse;
+  /** Delete multiple PaymentMethods */
+  deletePaymentMethods: Array<DeletionResponse>;
   /** Delete a Product */
   deleteProduct: DeletionResponse;
   /** Delete a ProductOption */
@@ -2633,21 +2643,32 @@ export type Mutation = {
   /** Delete multiple Products */
   deleteProducts: Array<DeletionResponse>;
   deletePromotion: DeletionResponse;
+  deletePromotions: Array<DeletionResponse>;
   /** Delete a Province */
   deleteProvince: DeletionResponse;
   /** Delete an existing Role */
   deleteRole: DeletionResponse;
+  /** Delete multiple Roles */
+  deleteRoles: Array<DeletionResponse>;
   /** Delete a Seller */
   deleteSeller: DeletionResponse;
+  /** Delete multiple Sellers */
+  deleteSellers: Array<DeletionResponse>;
   /** Delete a ShippingMethod */
   deleteShippingMethod: DeletionResponse;
+  /** Delete multiple ShippingMethods */
+  deleteShippingMethods: Array<DeletionResponse>;
   deleteStockLocation: DeletionResponse;
   /** Delete an existing Tag */
   deleteTag: DeletionResponse;
+  /** Deletes multiple TaxCategories */
+  deleteTaxCategories: Array<DeletionResponse>;
   /** Deletes a TaxCategory */
   deleteTaxCategory: DeletionResponse;
   /** Delete a TaxRate */
   deleteTaxRate: DeletionResponse;
+  /** Delete multiple TaxRates */
+  deleteTaxRates: Array<DeletionResponse>;
   /** Delete a Zone */
   deleteZone: DeletionResponse;
   flushBufferedJobs: Success;
@@ -3016,6 +3037,11 @@ export type MutationDeleteAdministratorArgs = {
 };
 
 
+export type MutationDeleteAdministratorsArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteAssetArgs = {
   input: DeleteAssetInput;
 };
@@ -3031,6 +3057,11 @@ export type MutationDeleteChannelArgs = {
 };
 
 
+export type MutationDeleteChannelsArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteCollectionArgs = {
   id: Scalars['ID'];
 };
@@ -3041,6 +3072,11 @@ export type MutationDeleteCollectionsArgs = {
 };
 
 
+export type MutationDeleteCountriesArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteCountryArgs = {
   id: Scalars['ID'];
 };
@@ -3066,6 +3102,11 @@ export type MutationDeleteCustomerNoteArgs = {
 };
 
 
+export type MutationDeleteCustomersArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteDraftOrderArgs = {
   orderId: Scalars['ID'];
 };
@@ -3100,6 +3141,12 @@ export type MutationDeletePaymentMethodArgs = {
 };
 
 
+export type MutationDeletePaymentMethodsArgs = {
+  force?: InputMaybe<Scalars['Boolean']>;
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteProductArgs = {
   id: Scalars['ID'];
 };
@@ -3130,6 +3177,11 @@ export type MutationDeletePromotionArgs = {
 };
 
 
+export type MutationDeletePromotionsArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteProvinceArgs = {
   id: Scalars['ID'];
 };
@@ -3140,16 +3192,31 @@ export type MutationDeleteRoleArgs = {
 };
 
 
+export type MutationDeleteRolesArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteSellerArgs = {
   id: Scalars['ID'];
 };
 
 
+export type MutationDeleteSellersArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteShippingMethodArgs = {
   id: Scalars['ID'];
 };
 
 
+export type MutationDeleteShippingMethodsArgs = {
+  ids?: InputMaybe<Array<Scalars['ID']>>;
+};
+
+
 export type MutationDeleteStockLocationArgs = {
   input: DeleteStockLocationInput;
 };
@@ -3160,6 +3227,11 @@ export type MutationDeleteTagArgs = {
 };
 
 
+export type MutationDeleteTaxCategoriesArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteTaxCategoryArgs = {
   id: Scalars['ID'];
 };
@@ -3170,6 +3242,11 @@ export type MutationDeleteTaxRateArgs = {
 };
 
 
+export type MutationDeleteTaxRatesArgs = {
+  ids: Array<Scalars['ID']>;
+};
+
+
 export type MutationDeleteZoneArgs = {
   id: Scalars['ID'];
 };
@@ -6317,6 +6394,13 @@ export type DeleteAdministratorMutationVariables = Exact<{
 
 export type DeleteAdministratorMutation = { deleteAdministrator: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteAdministratorsMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteAdministratorsMutation = { deleteAdministrators: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type GetRolesQueryVariables = Exact<{
   options?: InputMaybe<RoleListOptions>;
 }>;
@@ -6352,6 +6436,13 @@ export type DeleteRoleMutationVariables = Exact<{
 
 export type DeleteRoleMutation = { deleteRole: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteRolesMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteRolesMutation = { deleteRoles: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type AssignRoleToAdministratorMutationVariables = Exact<{
   administratorId: Scalars['ID'];
   roleId: Scalars['ID'];
@@ -6604,6 +6695,13 @@ export type DeleteCustomerMutationVariables = Exact<{
 
 export type DeleteCustomerMutation = { deleteCustomer: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteCustomersMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteCustomersMutation = { deleteCustomers: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type CreateCustomerAddressMutationVariables = Exact<{
   customerId: Scalars['ID'];
   input: CreateAddressInput;
@@ -7383,6 +7481,13 @@ export type DeletePromotionMutationVariables = Exact<{
 
 export type DeletePromotionMutation = { deletePromotion: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeletePromotionsMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeletePromotionsMutation = { deletePromotions: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type CountryFragment = { __typename?: 'Country', id: string, createdAt: any, updatedAt: any, code: string, name: string, enabled: boolean, translations: Array<{ __typename?: 'RegionTranslation', id: string, languageCode: LanguageCode, name: string }> };
 
 export type GetCountryListQueryVariables = Exact<{
@@ -7425,6 +7530,13 @@ export type DeleteCountryMutationVariables = Exact<{
 
 export type DeleteCountryMutation = { deleteCountry: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteCountriesMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteCountriesMutation = { deleteCountries: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type ZoneFragment = { __typename?: 'Zone', id: string, createdAt: any, updatedAt: any, name: string, members: Array<{ __typename?: 'Country', id: string, createdAt: any, updatedAt: any, code: string, name: string, enabled: boolean, translations: Array<{ __typename?: 'RegionTranslation', id: string, languageCode: LanguageCode, name: string }> } | { __typename?: 'Province' }> };
 
 export type GetZonesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -7513,6 +7625,13 @@ export type DeleteTaxCategoryMutationVariables = Exact<{
 
 export type DeleteTaxCategoryMutation = { deleteTaxCategory: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteTaxCategoriesMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteTaxCategoriesMutation = { deleteTaxCategories: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type TaxRateFragment = { __typename?: 'TaxRate', id: string, createdAt: any, updatedAt: any, name: string, enabled: boolean, value: number, category: { __typename?: 'TaxCategory', id: string, name: string }, zone: { __typename?: 'Zone', id: string, name: string }, customerGroup?: { __typename?: 'CustomerGroup', id: string, name: string } | null };
 
 export type GetTaxRateListQueryVariables = Exact<{
@@ -7557,6 +7676,13 @@ export type DeleteTaxRateMutationVariables = Exact<{
 
 export type DeleteTaxRateMutation = { deleteTaxRate: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteTaxRatesMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteTaxRatesMutation = { deleteTaxRates: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type ChannelFragment = { __typename?: 'Channel', id: string, createdAt: any, updatedAt: any, code: string, token: string, pricesIncludeTax: boolean, currencyCode: CurrencyCode, defaultLanguageCode: LanguageCode, defaultShippingZone?: { __typename?: 'Zone', id: string, name: string } | null, defaultTaxZone?: { __typename?: 'Zone', id: string, name: string } | null, seller?: { __typename?: 'Seller', id: string, name: string } | null };
 
 export type SellerFragment = { __typename?: 'Seller', id: string, createdAt: any, updatedAt: any, name: string };
@@ -7610,6 +7736,13 @@ export type DeleteSellerMutationVariables = Exact<{
 
 export type DeleteSellerMutation = { deleteSeller: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteSellersMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteSellersMutation = { deleteSellers: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type GetActiveChannelQueryVariables = Exact<{ [key: string]: never; }>;
 
 
@@ -7636,6 +7769,13 @@ export type DeleteChannelMutationVariables = Exact<{
 
 export type DeleteChannelMutation = { deleteChannel: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteChannelsMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteChannelsMutation = { deleteChannels: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type PaymentMethodFragment = { __typename?: 'PaymentMethod', id: string, createdAt: any, updatedAt: any, name: string, code: string, description: string, enabled: boolean, translations: Array<{ __typename?: 'PaymentMethodTranslation', id: string, languageCode: LanguageCode, name: string, description: string }>, checker?: { __typename?: 'ConfigurableOperation', code: string, args: Array<{ __typename?: 'ConfigArg', name: string, value: string }> } | null, handler: { __typename?: 'ConfigurableOperation', code: string, args: Array<{ __typename?: 'ConfigArg', name: string, value: string }> } };
 
 export type GetPaymentMethodListQueryVariables = Exact<{
@@ -7679,6 +7819,14 @@ export type DeletePaymentMethodMutationVariables = Exact<{
 
 export type DeletePaymentMethodMutation = { deletePaymentMethod: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeletePaymentMethodsMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+  force?: InputMaybe<Scalars['Boolean']>;
+}>;
+
+
+export type DeletePaymentMethodsMutation = { deletePaymentMethods: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type GlobalSettingsFragment = { __typename?: 'GlobalSettings', id: string, availableLanguages: Array<LanguageCode>, trackInventory: boolean, outOfStockThreshold: number, serverConfig: { __typename?: 'ServerConfig', permissions: Array<{ __typename?: 'PermissionDefinition', name: string, description: string, assignable: boolean }>, orderProcess: Array<{ __typename?: 'OrderProcessState', name: string }> } };
 
 export type GetGlobalSettingsQueryVariables = Exact<{ [key: string]: never; }>;
@@ -7938,6 +8086,13 @@ export type DeleteShippingMethodMutationVariables = Exact<{
 
 export type DeleteShippingMethodMutation = { deleteShippingMethod: { __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null } };
 
+export type DeleteShippingMethodsMutationVariables = Exact<{
+  ids: Array<Scalars['ID']> | Scalars['ID'];
+}>;
+
+
+export type DeleteShippingMethodsMutation = { deleteShippingMethods: Array<{ __typename?: 'DeletionResponse', result: DeletionResult, message?: string | null }> };
+
 export type TestShippingMethodQueryVariables = Exact<{
   input: TestShippingMethodInput;
 }>;

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

@@ -1,7 +1,14 @@
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
-import { lastValueFrom } from 'rxjs';
+import { lastValueFrom, Observable, of, switchMap } from 'rxjs';
+import { map } 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 { BaseListComponent } from '../base-list.component';
+import { DeletionResponse, DeletionResult } from '../generated-types';
 
 /**
  * @description
@@ -44,3 +51,113 @@ export function currentChannelIsNotDefault(dataService: DataService) {
         }),
     );
 }
+
+export type CreateBulkDeleteActionConfig<ItemType> = Pick<BulkAction, 'location' | 'requiresPermission'> & {
+    getItemName: (item: ItemType) => string;
+    shouldRetryItem?: (response: DeletionResponse, item: ItemType) => boolean;
+    bulkDelete: (
+        dataService: DataService,
+        ids: string[],
+        retrying: boolean,
+    ) => Observable<DeletionResponse[]>;
+};
+
+/**
+ * @description
+ * Creates a BulkAction which can be used to delete multiple items.
+ */
+export function createBulkDeleteAction<ItemType>(config: CreateBulkDeleteActionConfig<ItemType>) {
+    const bulkDeleteAction: BulkAction<any, BaseListComponent<any, any>> = {
+        location: config.location,
+        label: _('common.delete'),
+        icon: 'trash',
+        iconClass: 'is-danger',
+        requiresPermission: config.requiresPermission,
+        onClick: ({ injector, selection, hostComponent, clearSelection }) => {
+            const modalService = injector.get(ModalService);
+            const dataService = injector.get(DataService);
+            const notificationService = injector.get(NotificationService);
+
+            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: _('catalog.confirm-bulk-delete'),
+                        body: message ? message : nMore ? _('common.list-items-and-n-more') : itemNames,
+                        translationVars: { items: itemNames, nMore },
+                        buttons: [
+                            { type: 'secondary', label: _('common.cancel') },
+                            {
+                                type: 'danger',
+                                label: message ? _('common.force-delete') : _('common.delete'),
+                                returnValue: true,
+                            },
+                        ],
+                    })
+                    .pipe(
+                        switchMap(res =>
+                            res
+                                ? config.bulkDelete(
+                                      dataService,
+                                      selection.map(c => c.id),
+                                      message != null,
+                                  )
+                                : of([]),
+                        ),
+                    );
+            }
+
+            showModalAndDelete(selection)
+                .pipe(
+                    switchMap(result => {
+                        let deletedCount = 0;
+                        const errors: Array<{ item: ItemType; message: string }> = [];
+                        let i = 0;
+                        for (const item of result) {
+                            if (item.result === DeletionResult.DELETED) {
+                                deletedCount++;
+                            } else if (config.shouldRetryItem?.(result[i], selection[i])) {
+                                errors.push({ item: selection[i], message: item.message ?? '' });
+                            }
+                            i++;
+                        }
+                        if (0 < errors.length) {
+                            return showModalAndDelete(
+                                errors.map(e => e.item),
+                                errors.map(e => e.message).join('\n'),
+                            ).pipe(
+                                map(result2 => {
+                                    const deletedCount2 = result2.filter(
+                                        r => r.result === DeletionResult.DELETED,
+                                    ).length;
+                                    return deletedCount + deletedCount2;
+                                }),
+                            );
+                        } else {
+                            return of(deletedCount);
+                        }
+                    }),
+                )
+                .subscribe(deletedCount => {
+                    if (deletedCount) {
+                        hostComponent.refresh();
+                        clearSelection();
+                        notificationService.success(_('catalog.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'), {
+                            count: notDeletedCount,
+                        });
+                    }
+                });
+        },
+    };
+    return bulkDeleteAction;
+}

+ 1 - 0
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.html

@@ -7,6 +7,7 @@
                 [class.collapsible]="section.collapsible"
                 [class.collapsed]="section.collapsible && !expandedSections.includes(section.id)"
                 routerLinkActive="active"
+                (isActiveChange)="setExpanded(section, $event)"
                 *ngIf="shouldDisplayLink(section)"
             >
                 <vdr-ui-extension-point

+ 8 - 0
packages/admin-ui/src/lib/core/src/components/main-nav/main-nav.component.ts

@@ -34,6 +34,14 @@ export class MainNavComponent extends BaseNavComponent implements OnInit {
         }
     }
 
+    setExpanded(section: NavMenuSection, expanded: boolean) {
+        if (expanded) {
+            this.expandedSections.push(section.id);
+        } else {
+            this.expandedSections = this.expandedSections.filter(id => id !== section.id);
+        }
+    }
+
     getStyleForSection(section: NavMenuSection) {
         if (section.collapsible) {
             if (this.expandedSections.includes(section.id)) {

+ 18 - 0
packages/admin-ui/src/lib/core/src/data/definitions/administrator-definitions.ts

@@ -102,6 +102,15 @@ export const DELETE_ADMINISTRATOR = gql`
     }
 `;
 
+export const DELETE_ADMINISTRATORS = gql`
+    mutation DeleteAdministrators($ids: [ID!]!) {
+        deleteAdministrators(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const GET_ROLES = gql`
     query GetRoles($options: RoleListOptions) {
         roles(options: $options) {
@@ -150,6 +159,15 @@ export const DELETE_ROLE = gql`
     }
 `;
 
+export const DELETE_ROLES = gql`
+    mutation DeleteRoles($ids: [ID!]!) {
+        deleteRoles(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const ASSIGN_ROLE_TO_ADMINISTRATOR = gql`
     mutation AssignRoleToAdministrator($administratorId: ID!, $roleId: ID!) {
         assignRoleToAdministrator(administratorId: $administratorId, roleId: $roleId) {

+ 9 - 0
packages/admin-ui/src/lib/core/src/data/definitions/customer-definitions.ts

@@ -133,6 +133,15 @@ export const DELETE_CUSTOMER = gql`
     }
 `;
 
+export const DELETE_CUSTOMERS = gql`
+    mutation DeleteCustomers($ids: [ID!]!) {
+        deleteCustomers(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const CREATE_CUSTOMER_ADDRESS = gql`
     mutation CreateCustomerAddress($customerId: ID!, $input: CreateAddressInput!) {
         createCustomerAddress(customerId: $customerId, input: $input) {

+ 9 - 0
packages/admin-ui/src/lib/core/src/data/definitions/promotion-definitions.ts

@@ -95,3 +95,12 @@ export const DELETE_PROMOTION = gql`
         }
     }
 `;
+
+export const DELETE_PROMOTIONS = gql`
+    mutation DeletePromotions($ids: [ID!]!) {
+        deletePromotions(ids: $ids) {
+            result
+            message
+        }
+    }
+`;

+ 54 - 0
packages/admin-ui/src/lib/core/src/data/definitions/settings-definitions.ts

@@ -85,6 +85,15 @@ export const DELETE_COUNTRY = gql`
     }
 `;
 
+export const DELETE_COUNTRIES = gql`
+    mutation DeleteCountries($ids: [ID!]!) {
+        deleteCountries(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const ZONE_FRAGMENT = gql`
     fragment Zone on Zone {
         id
@@ -227,6 +236,15 @@ export const DELETE_TAX_CATEGORY = gql`
     }
 `;
 
+export const DELETE_TAX_CATEGORIES = gql`
+    mutation DeleteTaxCategories($ids: [ID!]!) {
+        deleteTaxCategories(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const TAX_RATE_FRAGMENT = gql`
     fragment TaxRate on TaxRate {
         id
@@ -322,6 +340,15 @@ export const DELETE_TAX_RATE = gql`
     }
 `;
 
+export const DELETE_TAX_RATES = gql`
+    mutation DeleteTaxRates($ids: [ID!]!) {
+        deleteTaxRates(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const CHANNEL_FRAGMENT = gql`
     fragment Channel on Channel {
         id
@@ -425,6 +452,15 @@ export const DELETE_SELLER = gql`
     }
 `;
 
+export const DELETE_SELLERS = gql`
+    mutation DeleteSellers($ids: [ID!]!) {
+        deleteSellers(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const GET_ACTIVE_CHANNEL = gql`
     query GetActiveChannel {
         activeChannel {
@@ -465,6 +501,15 @@ export const DELETE_CHANNEL = gql`
     }
 `;
 
+export const DELETE_CHANNELS = gql`
+    mutation DeleteChannels($ids: [ID!]!) {
+        deleteChannels(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const PAYMENT_METHOD_FRAGMENT = gql`
     fragment PaymentMethod on PaymentMethod {
         id
@@ -550,6 +595,15 @@ export const DELETE_PAYMENT_METHOD = gql`
     }
 `;
 
+export const DELETE_PAYMENT_METHODS = gql`
+    mutation DeletePaymentMethods($ids: [ID!]!, $force: Boolean) {
+        deletePaymentMethods(ids: $ids, force: $force) {
+            result
+            message
+        }
+    }
+`;
+
 export const GLOBAL_SETTINGS_FRAGMENT = gql`
     fragment GlobalSettings on GlobalSettings {
         id

+ 9 - 0
packages/admin-ui/src/lib/core/src/data/definitions/shipping-definitions.ts

@@ -90,6 +90,15 @@ export const DELETE_SHIPPING_METHOD = gql`
     }
 `;
 
+export const DELETE_SHIPPING_METHODS = gql`
+    mutation DeleteShippingMethods($ids: [ID!]!) {
+        deleteShippingMethods(ids: $ids) {
+            result
+            message
+        }
+    }
+`;
+
 export const TEST_SHIPPING_METHOD = gql`
     query TestShippingMethod($input: TestShippingMethodInput!) {
         testShippingMethod(input: $input) {

+ 18 - 0
packages/admin-ui/src/lib/core/src/data/providers/administrator-data.service.ts

@@ -5,7 +5,9 @@ import {
     CREATE_ADMINISTRATOR,
     CREATE_ROLE,
     DELETE_ADMINISTRATOR,
+    DELETE_ADMINISTRATORS,
     DELETE_ROLE,
+    DELETE_ROLES,
     GET_ACTIVE_ADMINISTRATOR,
     GET_ADMINISTRATOR,
     GET_ADMINISTRATORS,
@@ -74,6 +76,13 @@ export class AdministratorDataService {
         >(DELETE_ADMINISTRATOR, { id });
     }
 
+    deleteAdministrators(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteAdministratorsMutation,
+            Codegen.DeleteAdministratorsMutationVariables
+        >(DELETE_ADMINISTRATORS, { ids });
+    }
+
     getRoles(take: number = 10, skip: number = 0) {
         return this.baseDataService.query<Codegen.GetRolesQuery, Codegen.GetRolesQueryVariables>(GET_ROLES, {
             options: {
@@ -115,4 +124,13 @@ export class AdministratorDataService {
             },
         );
     }
+
+    deleteRoles(ids: string[]) {
+        return this.baseDataService.mutate<Codegen.DeleteRolesMutation, Codegen.DeleteRolesMutationVariables>(
+            DELETE_ROLES,
+            {
+                ids,
+            },
+        );
+    }
 }

+ 8 - 0
packages/admin-ui/src/lib/core/src/data/providers/customer-data.service.ts

@@ -20,6 +20,7 @@ import {
     UPDATE_CUSTOMER_ADDRESS,
     UPDATE_CUSTOMER_GROUP,
     UPDATE_CUSTOMER_NOTE,
+    DELETE_CUSTOMERS,
 } from '../definitions/customer-definitions';
 
 import { BaseDataService } from './base-data.service';
@@ -89,6 +90,13 @@ export class CustomerDataService {
         >(DELETE_CUSTOMER, { id });
     }
 
+    deleteCustomers(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteCustomersMutation,
+            Codegen.DeleteCustomersMutationVariables
+        >(DELETE_CUSTOMERS, { ids });
+    }
+
     createCustomerAddress(customerId: string, input: Codegen.CreateAddressInput) {
         return this.baseDataService.mutate<
             Codegen.CreateCustomerAddressMutation,

+ 8 - 0
packages/admin-ui/src/lib/core/src/data/providers/promotion-data.service.ts

@@ -4,6 +4,7 @@ import * as Codegen from '../../common/generated-types';
 import {
     CREATE_PROMOTION,
     DELETE_PROMOTION,
+    DELETE_PROMOTIONS,
     GET_ADJUSTMENT_OPERATIONS,
     GET_PROMOTION,
     GET_PROMOTION_LIST,
@@ -86,4 +87,11 @@ export class PromotionDataService {
             Codegen.DeletePromotionMutationVariables
         >(DELETE_PROMOTION, { id });
     }
+
+    deletePromotions(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeletePromotionsMutation,
+            Codegen.DeletePromotionsMutationVariables
+        >(DELETE_PROMOTIONS, { ids });
+    }
 }

+ 62 - 1
packages/admin-ui/src/lib/core/src/data/providers/settings-data.service.ts

@@ -57,6 +57,12 @@ import {
     UPDATE_TAX_CATEGORY,
     UPDATE_TAX_RATE,
     UPDATE_ZONE,
+    DELETE_SELLERS,
+    DELETE_CHANNELS,
+    DELETE_PAYMENT_METHODS,
+    DELETE_TAX_CATEGORIES,
+    DELETE_TAX_RATES,
+    DELETE_COUNTRIES,
 } from '../definitions/settings-definitions';
 
 import { BaseDataService } from './base-data.service';
@@ -117,6 +123,15 @@ export class SettingsDataService {
         });
     }
 
+    deleteCountries(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteCountriesMutation,
+            Codegen.DeleteCountriesMutationVariables
+        >(DELETE_COUNTRIES, {
+            ids,
+        });
+    }
+
     getZones() {
         return this.baseDataService.query<Codegen.GetZonesQuery>(GET_ZONES);
     }
@@ -213,12 +228,21 @@ export class SettingsDataService {
     deleteTaxCategory(id: string) {
         return this.baseDataService.mutate<
             Codegen.DeleteTaxCategoryMutation,
-            Codegen.DeleteTaxRateMutationVariables
+            Codegen.DeleteTaxCategoryMutationVariables
         >(DELETE_TAX_CATEGORY, {
             id,
         });
     }
 
+    deleteTaxCategories(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteTaxCategoriesMutation,
+            Codegen.DeleteTaxCategoriesMutationVariables
+        >(DELETE_TAX_CATEGORIES, {
+            ids,
+        });
+    }
+
     getTaxRates(take: number = 10, skip: number = 0, fetchPolicy?: FetchPolicy) {
         return this.baseDataService.query<Codegen.GetTaxRateListQuery, Codegen.GetTaxRateListQueryVariables>(
             GET_TAX_RATE_LIST,
@@ -284,6 +308,15 @@ export class SettingsDataService {
         });
     }
 
+    deleteTaxRates(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteTaxRatesMutation,
+            Codegen.DeleteTaxRatesMutationVariables
+        >(DELETE_TAX_RATES, {
+            ids,
+        });
+    }
+
     getChannels(options: ChannelListOptions = {}) {
         return this.baseDataService.query<Codegen.GetChannelsQuery, Codegen.GetChannelsQueryVariables>(
             GET_CHANNELS,
@@ -343,6 +376,15 @@ export class SettingsDataService {
         });
     }
 
+    deleteSellers(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteSellersMutation,
+            Codegen.DeleteSellersMutationVariables
+        >(DELETE_SELLERS, {
+            ids,
+        });
+    }
+
     getActiveChannel(fetchPolicy?: FetchPolicy) {
         return this.baseDataService.query<
             Codegen.GetActiveChannelQuery,
@@ -377,6 +419,15 @@ export class SettingsDataService {
         });
     }
 
+    deleteChannels(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteChannelsMutation,
+            Codegen.DeleteChannelsMutationVariables
+        >(DELETE_CHANNELS, {
+            ids,
+        });
+    }
+
     getPaymentMethods(take: number = 10, skip: number = 0) {
         return this.baseDataService.query<
             Codegen.GetPaymentMethodListQuery,
@@ -434,6 +485,16 @@ export class SettingsDataService {
         });
     }
 
+    deletePaymentMethods(ids: string[], force: boolean) {
+        return this.baseDataService.mutate<
+            Codegen.DeletePaymentMethodsMutation,
+            Codegen.DeletePaymentMethodsMutationVariables
+        >(DELETE_PAYMENT_METHODS, {
+            ids,
+            force,
+        });
+    }
+
     getPaymentMethodOperations() {
         return this.baseDataService.query<Codegen.GetPaymentMethodOperationsQuery>(
             GET_PAYMENT_METHOD_OPERATIONS,

+ 10 - 0
packages/admin-ui/src/lib/core/src/data/providers/shipping-method-data.service.ts

@@ -4,6 +4,7 @@ import * as Codegen from '../../common/generated-types';
 import {
     CREATE_SHIPPING_METHOD,
     DELETE_SHIPPING_METHOD,
+    DELETE_SHIPPING_METHODS,
     GET_SHIPPING_METHOD,
     GET_SHIPPING_METHOD_LIST,
     GET_SHIPPING_METHOD_OPERATIONS,
@@ -88,6 +89,15 @@ export class ShippingMethodDataService {
         });
     }
 
+    deleteShippingMethods(ids: string[]) {
+        return this.baseDataService.mutate<
+            Codegen.DeleteShippingMethodsMutation,
+            Codegen.DeleteShippingMethodsMutationVariables
+        >(DELETE_SHIPPING_METHODS, {
+            ids,
+        });
+    }
+
     testShippingMethod(input: Codegen.TestShippingMethodInput) {
         return this.baseDataService.query<
             Codegen.TestShippingMethodQuery,

+ 15 - 1
packages/admin-ui/src/lib/core/src/providers/bulk-action-registry/bulk-action-types.ts

@@ -9,7 +9,21 @@ import { ActivatedRoute } from '@angular/router';
  * @docsCategory bulk-actions
  * @docsPage BulkAction
  */
-export type BulkActionLocationId = 'product-list' | 'facet-list' | 'collection-list' | string;
+export type BulkActionLocationId =
+    | 'product-list'
+    | 'facet-list'
+    | 'collection-list'
+    | 'customer-list'
+    | 'promotion-list'
+    | 'seller-list'
+    | 'channel-list'
+    | 'administrator-list'
+    | 'role-list'
+    | 'shipping-method-list'
+    | 'payment-method-list'
+    | 'tax-category-list'
+    | 'tax-rate-list'
+    | string;
 
 /**
  * @description

+ 0 - 1
packages/admin-ui/src/lib/core/src/shared/components/data-table-2/data-table2.component.scss

@@ -8,7 +8,6 @@
 
 .bulk-actions {
     margin-top: 4px;
-    min-height: 40px;
     padding-left: calc(var(--space-unit) * 4);
 }
 

+ 4 - 0
packages/admin-ui/src/lib/core/src/shared/components/language-selector/language-selector.component.scss

@@ -1,3 +1,7 @@
+:host {
+    display: block;
+}
+
 .code {
     color: var(--color-grey-400);
 }

+ 10 - 0
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list-bulk-actions.ts

@@ -0,0 +1,10 @@
+import { createBulkDeleteAction, GetCustomerListQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteCustomersBulkAction = createBulkDeleteAction<ItemOf<GetCustomerListQuery, 'customers'>>({
+    location: 'customer-list',
+    requiresPermission: userPermissions => userPermissions.includes(Permission.DeleteCustomer),
+    getItemName: item => item.firstName + ' ' + item.lastName,
+    bulkDelete: (dataService, ids) =>
+        dataService.customer.deleteCustomers(ids).pipe(map(res => res.deleteCustomers)),
+});

+ 1 - 1
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.html

@@ -21,7 +21,7 @@
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
         <vdr-bulk-action-menu
-            locationId="facet-list"
+            locationId="customer-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
         ></vdr-bulk-action-menu>

+ 1 - 33
packages/admin-ui/src/lib/customer/src/components/customer-list/customer-list.component.ts

@@ -10,11 +10,7 @@ import {
     GetCustomerListQuery,
     ItemOf,
     LogicalOperator,
-    ModalService,
-    NotificationService,
 } from '@vendure/admin-ui/core';
-import { EMPTY } from 'rxjs';
-import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-customer-list',
@@ -58,11 +54,9 @@ export class CustomerListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
         router: Router,
         route: ActivatedRoute,
-        private modalService: ModalService,
-        private notificationService: NotificationService,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -96,30 +90,4 @@ export class CustomerListComponent
         super.ngOnInit();
         super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
-
-    deleteCustomer(customer: ItemOf<GetCustomerListQuery, 'customers'>) {
-        return this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-customer'),
-                body: `${customer.firstName} ${customer.lastName}`,
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(switchMap(res => (res ? this.dataService.customer.deleteCustomer(customer.id) : EMPTY)))
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'Customer',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Customer',
-                    });
-                },
-            );
-    }
 }

+ 7 - 2
packages/admin-ui/src/lib/customer/src/customer.module.ts

@@ -1,6 +1,6 @@
 import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
-import { SharedModule } from '@vendure/admin-ui/core';
+import { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';
 
 import { AddCustomerToGroupDialogComponent } from './components/add-customer-to-group-dialog/add-customer-to-group-dialog.component';
 import { AddressCardComponent } from './components/address-card/address-card.component';
@@ -11,6 +11,7 @@ import { CustomerGroupListComponent } from './components/customer-group-list/cus
 import { CustomerGroupMemberListComponent } from './components/customer-group-member-list/customer-group-member-list.component';
 import { CustomerHistoryEntryHostComponent } from './components/customer-history/customer-history-entry-host.component';
 import { CustomerHistoryComponent } from './components/customer-history/customer-history.component';
+import { deleteCustomersBulkAction } from './components/customer-list/customer-list-bulk-actions';
 import { CustomerListComponent } from './components/customer-list/customer-list.component';
 import { CustomerStatusLabelComponent } from './components/customer-status-label/customer-status-label.component';
 import { SelectCustomerGroupDialogComponent } from './components/select-customer-group-dialog/select-customer-group-dialog.component';
@@ -34,4 +35,8 @@ import { customerRoutes } from './customer.routes';
     ],
     exports: [AddressCardComponent],
 })
-export class CustomerModule {}
+export class CustomerModule {
+    constructor(private bulkActionRegistryService: BulkActionRegistryService) {
+        bulkActionRegistryService.registerBulkAction(deleteCustomersBulkAction);
+    }
+}

+ 12 - 0
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list-bulk-actions.ts

@@ -0,0 +1,12 @@
+import { createBulkDeleteAction, GetPromotionListQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deletePromotionsBulkAction = createBulkDeleteAction<ItemOf<GetPromotionListQuery, 'promotions'>>(
+    {
+        location: 'promotion-list',
+        requiresPermission: userPermissions => userPermissions.includes(Permission.DeletePromotion),
+        getItemName: item => item.name,
+        bulkDelete: (dataService, ids) =>
+            dataService.promotion.deletePromotions(ids).pipe(map(res => res.deletePromotions)),
+    },
+);

+ 1 - 1
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.html

@@ -21,7 +21,7 @@
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
         <vdr-bulk-action-menu
-            locationId="facet-list"
+            locationId="promotion-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
         />

+ 2 - 39
packages/admin-ui/src/lib/marketing/src/components/promotion-list/promotion-list.component.ts

@@ -1,23 +1,17 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
+    DataTableService,
     GetPromotionListQuery,
     ItemOf,
     LogicalOperator,
-    ModalService,
-    NotificationService,
     PromotionFilterParameter,
     PromotionListOptions,
     PromotionSortParameter,
-    SelectionManager,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, switchMap, takeUntil } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
 
 export type PromotionSearchForm = {
     name: string;
@@ -94,11 +88,9 @@ export class PromotionListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
         router: Router,
         route: ActivatedRoute,
-        private notificationService: NotificationService,
-        private modalService: ModalService,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -114,35 +106,6 @@ export class PromotionListComponent
         super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
 
-    deletePromotion(promotionId: string) {
-        this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-promotion'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(response =>
-                    response ? this.dataService.promotion.deletePromotion(promotionId) : EMPTY,
-                ),
-            )
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'Promotion',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Promotion',
-                    });
-                },
-            );
-    }
-
     private createQueryOptions(
         skip: number,
         take: number,

+ 7 - 2
packages/admin-ui/src/lib/marketing/src/marketing.module.ts

@@ -1,8 +1,9 @@
 import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
-import { SharedModule } from '@vendure/admin-ui/core';
+import { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';
 
 import { PromotionDetailComponent } from './components/promotion-detail/promotion-detail.component';
+import { deletePromotionsBulkAction } from './components/promotion-list/promotion-list-bulk-actions';
 import { PromotionListComponent } from './components/promotion-list/promotion-list.component';
 import { marketingRoutes } from './marketing.routes';
 
@@ -10,4 +11,8 @@ import { marketingRoutes } from './marketing.routes';
     imports: [SharedModule, RouterModule.forChild(marketingRoutes)],
     declarations: [PromotionListComponent, PromotionDetailComponent],
 })
-export class MarketingModule {}
+export class MarketingModule {
+    constructor(private bulkActionRegistryService: BulkActionRegistryService) {
+        bulkActionRegistryService.registerBulkAction(deletePromotionsBulkAction);
+    }
+}

+ 13 - 8
packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.html

@@ -8,14 +8,14 @@
             </a>
         </ng-container>
     </vdr-page-title>
- <!--   <vdr-page-header-description>Description of the current page (if applicable)</vdr-page-header-description>
-    <vdr-page-header-tabs
-        [tabs]="[
-            { id: 'tab1', label: 'Tab 1' },
-            { id: 'tab2', label: 'Tab 2' },
-            { id: 'tab3', label: 'Tab 3' }
-        ]"
-    ></vdr-page-header-tabs>-->
+    <!--   <vdr-page-header-description>Description of the current page (if applicable)</vdr-page-header-description>
+       <vdr-page-header-tabs
+           [tabs]="[
+               { id: 'tab1', label: 'Tab 1' },
+               { id: 'tab2', label: 'Tab 2' },
+               { id: 'tab3', label: 'Tab 3' }
+           ]"
+       ></vdr-page-header-tabs>-->
 </vdr-page-header>
 <vdr-page-body>
     <vdr-data-table-2
@@ -29,6 +29,11 @@
         (pageChange)="setPageNumber($event)"
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
+        <vdr-bulk-action-menu
+            locationId="order-list"
+            [hostComponent]="this"
+            [selectionManager]="selectionManager"
+        ></vdr-bulk-action-menu>
         <vdr-dt2-search
             [searchTermControl]="searchTermControl"
             [searchTermPlaceholder]="'order.search-by-order-filters' | translate"

+ 12 - 0
packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list-bulk-actions.ts

@@ -0,0 +1,12 @@
+import { createBulkDeleteAction, GetAdministratorsQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteAdministratorsBulkAction = createBulkDeleteAction<
+    ItemOf<GetAdministratorsQuery, 'administrators'>
+>({
+    location: 'administrator-list',
+    requiresPermission: userPermissions => userPermissions.includes(Permission.DeleteAdministrator),
+    getItemName: item => item.firstName + ' ' + item.lastName,
+    bulkDelete: (dataService, ids) =>
+        dataService.administrator.deleteAdministrators(ids).pipe(map(res => res.deleteAdministrators)),
+});

+ 17 - 0
packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list-bulk-actions.ts

@@ -0,0 +1,17 @@
+import {
+    createBulkDeleteAction,
+    GetChannelsQuery,
+    GetCustomerListQuery,
+    ItemOf,
+    Permission,
+} from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteChannelsBulkAction = createBulkDeleteAction<ItemOf<GetChannelsQuery, 'channels'>>({
+    location: 'channel-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.SuperAdmin) || userPermissions.includes(Permission.DeleteChannel),
+    getItemName: item => item.code,
+    bulkDelete: (dataService, ids) =>
+        dataService.settings.deleteChannels(ids).pipe(map(res => res.deleteChannels)),
+});

+ 1 - 33
packages/admin-ui/src/lib/settings/src/components/channel-list/channel-list.component.ts

@@ -6,15 +6,13 @@ import {
     ChannelFilterParameter,
     ChannelSortParameter,
     DataService,
+    DataTableService,
     GetChannelsQuery,
     ItemOf,
     ModalService,
     NotificationService,
 } from '@vendure/admin-ui/core';
 import { DEFAULT_CHANNEL_CODE } from '@vendure/common/lib/shared-constants';
-import { EMPTY } from 'rxjs';
-import { mergeMap, switchMap } from 'rxjs/operators';
-import { DataTableService } from '../../../../core/src/providers/data-table/data-table.service';
 
 @Component({
     selector: 'vdr-channel-list',
@@ -88,34 +86,4 @@ export class ChannelListComponent
     isDefaultChannel(channelCode: string): boolean {
         return channelCode === DEFAULT_CHANNEL_CODE;
     }
-
-    deleteChannel(id: string) {
-        this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-channel'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(response => (response ? this.dataService.settings.deleteChannel(id) : EMPTY)),
-                mergeMap(() => this.dataService.auth.currentUser().single$),
-                // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-                mergeMap(data => this.dataService.client.updateUserChannels(data.me!.channels)),
-            )
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'Channel',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Channel',
-                    });
-                },
-            );
-    }
 }

+ 12 - 0
packages/admin-ui/src/lib/settings/src/components/country-list/country-list-bulk-actions.ts

@@ -0,0 +1,12 @@
+import { createBulkDeleteAction, GetCountryListQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteCountriesBulkAction = createBulkDeleteAction<ItemOf<GetCountryListQuery, 'countries'>>({
+    location: 'country-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.DeleteSettings) ||
+        userPermissions.includes(Permission.DeleteCountry),
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.settings.deleteCountries(ids).pipe(map(res => res.deleteCountries)),
+});

+ 1 - 0
packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.html

@@ -13,6 +13,7 @@
 </vdr-page-header>
 <vdr-page-body>
     <vdr-language-selector
+        class="mx-4 my-2"
         [availableLanguageCodes]="availableLanguages$ | async"
         [currentLanguageCode]="contentLanguage$ | async"
         (languageCodeChange)="setLanguage($event)"

+ 3 - 42
packages/admin-ui/src/lib/settings/src/components/country-list/country-list.component.ts

@@ -7,16 +7,12 @@ import {
     CountrySortParameter,
     DataService,
     DataTableService,
-    DeletionResult,
     GetCountryListQuery,
     ItemOf,
     LanguageCode,
-    ModalService,
-    NotificationService,
     ServerConfigService,
 } from '@vendure/admin-ui/core';
-import { EMPTY, Observable } from 'rxjs';
-import { switchMap } from 'rxjs/operators';
+import { Observable } from 'rxjs';
 
 @Component({
     selector: 'vdr-country-list',
@@ -57,12 +53,10 @@ export class CountryListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
-        private notificationService: NotificationService,
-        private modalService: ModalService,
-        private serverConfigService: ServerConfigService,
         route: ActivatedRoute,
         router: Router,
+        private dataService: DataService,
+        private serverConfigService: ServerConfigService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -98,37 +92,4 @@ export class CountryListComponent
     setLanguage(code: LanguageCode) {
         this.dataService.client.setContentLanguage(code).subscribe();
     }
-
-    deleteCountry(countryId: string) {
-        this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-country'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(response =>
-                    response ? this.dataService.settings.deleteCountry(countryId) : EMPTY,
-                ),
-            )
-            .subscribe(
-                response => {
-                    if (response.deleteCountry.result === DeletionResult.DELETED) {
-                        this.notificationService.success(_('common.notify-delete-success'), {
-                            entity: 'Country',
-                        });
-                        this.dataService.settings.getCountries(999, 0).single$.subscribe();
-                    } else {
-                        this.notificationService.error(response.deleteCountry.message || '');
-                    }
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Country',
-                    });
-                },
-            );
-    }
 }

+ 20 - 0
packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list-bulk-actions.ts

@@ -0,0 +1,20 @@
+import {
+    createBulkDeleteAction,
+    GetPaymentMethodListQuery,
+    ItemOf,
+    Permission,
+} from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteFacetsBulkAction = createBulkDeleteAction<
+    ItemOf<GetPaymentMethodListQuery, 'paymentMethods'>
+>({
+    location: 'payment-method-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.DeletePaymentMethod) ||
+        userPermissions.includes(Permission.DeleteSettings),
+    getItemName: item => item.name,
+    shouldRetryItem: (response, item) => !!response.message,
+    bulkDelete: (dataService, ids, retrying) =>
+        dataService.settings.deletePaymentMethods(ids, retrying).pipe(map(res => res.deletePaymentMethods)),
+});

+ 6 - 45
packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.html

@@ -1,48 +1,3 @@
-<vdr-data-table
-    [items]="items$ | async"
-    [itemsPerPage]="itemsPerPage$ | async"
-    [totalItems]="totalItems$ | async"
-    [currentPage]="currentPage$ | async"
-    (pageChange)="setPageNumber($event)"
-    (itemsPerPageChange)="setItemsPerPage($event)"
->
-    <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>
-    <vdr-dt-column>{{ 'common.enabled' | translate }}</vdr-dt-column>
-    <vdr-dt-column></vdr-dt-column>
-    <vdr-dt-column></vdr-dt-column>
-    <ng-template let-paymentMethod="item">
-        <td class="left align-middle">{{ paymentMethod.code }}</td>
-        <td class="left align-middle">{{ paymentMethod.enabled }}</td>
-        <td class="right align-middle">
-            <vdr-table-row-action
-                iconShape="edit"
-                [label]="'common.edit' | translate"
-                [linkTo]="['./', paymentMethod.id]"
-            ></vdr-table-row-action>
-        </td>
-        <td class="right align-middle">
-            <vdr-dropdown>
-                <button type="button" class="btn btn-link btn-sm" vdrDropdownTrigger>
-                    {{ 'common.actions' | translate }}
-                    <clr-icon shape="caret down"></clr-icon>
-                </button>
-                <vdr-dropdown-menu vdrPosition="bottom-right">
-                    <button
-                        type="button"
-                        class="delete-button"
-                        (click)="deletePaymentMethod(paymentMethod.id)"
-                        [disabled]="!(['DeleteSettings', 'DeletePaymentMethod'] | hasPermission)"
-                        vdrDropdownItem
-                    >
-                        <clr-icon shape="trash" class="is-danger"></clr-icon>
-                        {{ 'common.delete' | translate }}
-                    </button>
-                </vdr-dropdown-menu>
-            </vdr-dropdown>
-        </td>
-    </ng-template>
-</vdr-data-table>
-
 <vdr-page-header>
     <vdr-page-title>
         <vdr-action-bar-items locationId="payment-method-list"></vdr-action-bar-items>
@@ -57,6 +12,12 @@
     </vdr-page-title>
 </vdr-page-header>
 <vdr-page-body>
+    <vdr-language-selector
+        class="mx-4 my-2"
+        [availableLanguageCodes]="availableLanguages$ | async"
+        [currentLanguageCode]="contentLanguage$ | async"
+        (languageCodeChange)="setLanguage($event)"
+    ></vdr-language-selector>
     <vdr-data-table-2
         class="mt-2"
         id="payment-method-list"

+ 15 - 82
packages/admin-ui/src/lib/settings/src/components/payment-method-list/payment-method-list.component.ts

@@ -1,23 +1,18 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
     DataTableService,
-    DeletionResult,
-    GetFacetListQuery,
     GetPaymentMethodListQuery,
     ItemOf,
-    ModalService,
-    NotificationService,
+    LanguageCode,
     PaymentMethodFilterParameter,
     PaymentMethodSortParameter,
-    SelectionManager,
+    ServerConfigService,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge } from 'rxjs';
-import { debounceTime, filter, map, switchMap, takeUntil } from 'rxjs/operators';
+import { Observable } from 'rxjs';
 
 @Component({
     selector: 'vdr-payment-method-list',
@@ -29,27 +24,11 @@ export class PaymentMethodListComponent
     extends BaseListComponent<GetPaymentMethodListQuery, ItemOf<GetPaymentMethodListQuery, 'paymentMethods'>>
     implements OnInit
 {
-    searchTermControl = new FormControl('');
-    selectionManager = new SelectionManager<ItemOf<GetFacetListQuery, 'facets'>>({
-        multiSelect: true,
-        itemsAreEqual: (a, b) => a.id === b.id,
-        additiveMode: true,
-    });
-
+    availableLanguages$: Observable<LanguageCode[]>;
+    contentLanguage$: Observable<LanguageCode>;
     readonly filters = this.dataTableService
         .createFilterCollection<PaymentMethodFilterParameter>()
-        .addFilter({
-            name: 'createdAt',
-            type: { kind: 'dateRange' },
-            label: _('common.created-at'),
-            filterField: 'createdAt',
-        })
-        .addFilter({
-            name: 'updatedAt',
-            type: { kind: 'dateRange' },
-            label: _('common.updated-at'),
-            filterField: 'updatedAt',
-        })
+        .addDateFilters()
         .addFilter({
             name: 'name',
             type: { kind: 'text' },
@@ -87,12 +66,11 @@ export class PaymentMethodListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
         router: Router,
         route: ActivatedRoute,
-        private modalService: ModalService,
-        private notificationService: NotificationService,
+        private dataService: DataService,
         private dataTableService: DataTableService,
+        private serverConfigService: ServerConfigService,
     ) {
         super(router, route);
         super.setQueryFn(
@@ -116,60 +94,15 @@ export class PaymentMethodListComponent
 
     ngOnInit() {
         super.ngOnInit();
-        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
-            filter(value => value != null && (2 <= value.length || value.length === 0)),
-            debounceTime(250),
-        );
-        merge(searchTerm$, this.filters.valueChanges, this.sorts.valueChanges)
-            .pipe(takeUntil(this.destroy$))
-            .subscribe(() => this.refresh());
-    }
+        this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();
+        this.contentLanguage$ = this.dataService.client
+            .uiState()
+            .mapStream(({ uiState }) => uiState.contentLanguage);
 
-    deletePaymentMethod(paymentMethodId: string) {
-        this.showModalAndDelete(paymentMethodId)
-            .pipe(
-                switchMap(response => {
-                    if (response.result === DeletionResult.DELETED) {
-                        return [true];
-                    } else {
-                        return this.showModalAndDelete(paymentMethodId, response.message || '').pipe(
-                            map(r => r.result === DeletionResult.DELETED),
-                        );
-                    }
-                }),
-                // Refresh the cached facets to reflect the changes
-                switchMap(() => this.dataService.settings.getPaymentMethods(100).single$),
-            )
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'PaymentMethod',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'PaymentMethod',
-                    });
-                },
-            );
+        super.refreshListOnChanges(this.contentLanguage$, this.filters.valueChanges, this.sorts.valueChanges);
     }
 
-    private showModalAndDelete(paymentMethodId: string, message?: string) {
-        return this.modalService
-            .dialog({
-                title: _('settings.confirm-delete-payment-method'),
-                body: message,
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(res =>
-                    res ? this.dataService.settings.deletePaymentMethod(paymentMethodId, !!message) : EMPTY,
-                ),
-                map(res => res.deletePaymentMethod),
-            );
+    setLanguage(code: LanguageCode) {
+        this.dataService.client.setContentLanguage(code).subscribe();
     }
 }

+ 10 - 0
packages/admin-ui/src/lib/settings/src/components/role-list/role-list-bulk-actions.ts

@@ -0,0 +1,10 @@
+import { createBulkDeleteAction, GetRolesQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteRolesBulkAction = createBulkDeleteAction<ItemOf<GetRolesQuery, 'roles'>>({
+    location: 'role-list',
+    requiresPermission: userPermissions => userPermissions.includes(Permission.DeleteAdministrator),
+    getItemName: item => item.description,
+    bulkDelete: (dataService, ids) =>
+        dataService.administrator.deleteRoles(ids).pipe(map(res => res.deleteRoles)),
+});

+ 1 - 32
packages/admin-ui/src/lib/settings/src/components/role-list/role-list.component.ts

@@ -7,15 +7,11 @@ import {
     DataTableService,
     GetRolesQuery,
     ItemOf,
-    ModalService,
-    NotificationService,
     Role,
     RoleFilterParameter,
     RoleSortParameter,
 } from '@vendure/admin-ui/core';
 import { CUSTOMER_ROLE_CODE, SUPER_ADMIN_ROLE_CODE } from '@vendure/common/lib/shared-constants';
-import { EMPTY } from 'rxjs';
-import { switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-role-list',
@@ -50,11 +46,9 @@ export class RoleListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private modalService: ModalService,
-        private notificationService: NotificationService,
-        private dataService: DataService,
         router: Router,
         route: ActivatedRoute,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -93,29 +87,4 @@ export class RoleListComponent
     isDefaultRole(role: Role): boolean {
         return role.code === SUPER_ADMIN_ROLE_CODE || role.code === CUSTOMER_ROLE_CODE;
     }
-
-    deleteRole(id: string) {
-        this.modalService
-            .dialog({
-                title: _('settings.confirm-delete-role'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(switchMap(response => (response ? this.dataService.administrator.deleteRole(id) : EMPTY)))
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'Role',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Role',
-                    });
-                },
-            );
-    }
 }

+ 10 - 0
packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list-bulk-actions.ts

@@ -0,0 +1,10 @@
+import { createBulkDeleteAction, GetSellersQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteSellersBulkAction = createBulkDeleteAction<ItemOf<GetSellersQuery, 'sellers'>>({
+    location: 'seller-list',
+    requiresPermission: userPermissions => userPermissions.includes(Permission.DeleteSeller),
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.settings.deleteSellers(ids).pipe(map(res => res.deleteSellers)),
+});

+ 1 - 32
packages/admin-ui/src/lib/settings/src/components/seller-list/seller-list.component.ts

@@ -1,18 +1,14 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
-import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
     BaseListComponent,
     DataService,
     DataTableService,
     GetSellersQuery,
     ItemOf,
-    ModalService,
-    NotificationService,
     SellerFilterParameter,
     SellerSortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY, switchMap } from 'rxjs';
 
 @Component({
     selector: 'vdr-seller-list',
@@ -38,11 +34,9 @@ export class SellerListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
-        private modalService: ModalService,
-        private notificationService: NotificationService,
         route: ActivatedRoute,
         router: Router,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -69,29 +63,4 @@ export class SellerListComponent
         super.ngOnInit();
         super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
-
-    deleteSeller(id: string) {
-        this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-seller'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(switchMap(response => (response ? this.dataService.settings.deleteSeller(id) : EMPTY)))
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'Seller',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'Seller',
-                    });
-                },
-            );
-    }
 }

+ 18 - 0
packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list-bulk-actions.ts

@@ -0,0 +1,18 @@
+import {
+    createBulkDeleteAction,
+    GetRolesQuery,
+    GetShippingMethodListQuery,
+    ItemOf,
+    Permission,
+} from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteShippingMethodsBulkAction = createBulkDeleteAction<
+    ItemOf<GetShippingMethodListQuery, 'shippingMethods'>
+>({
+    location: 'shipping-method-list',
+    requiresPermission: userPermissions => userPermissions.includes(Permission.DeleteShippingMethod),
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.shippingMethod.deleteShippingMethods(ids).pipe(map(res => res.deleteShippingMethods)),
+});

+ 3 - 2
packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.html

@@ -13,13 +13,14 @@
 </vdr-page-header>
 <vdr-page-body>
     <vdr-language-selector
+        class="mx-4 my-2"
         [availableLanguageCodes]="availableLanguages$ | async"
         [currentLanguageCode]="contentLanguage$ | async"
         (languageCodeChange)="setLanguage($event)"
     ></vdr-language-selector>
     <vdr-data-table-2
         class="mt-2"
-        id="shippingMethod-list"
+        id="shipping-method-list"
         [items]="items$ | async"
         [itemsPerPage]="itemsPerPage$ | async"
         [totalItems]="totalItems$ | async"
@@ -29,7 +30,7 @@
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
         <vdr-bulk-action-menu
-            locationId="shippingMethod-list"
+            locationId="shipping-method-list"
             [hostComponent]="this"
             [selectionManager]="selectionManager"
         />

+ 4 - 40
packages/admin-ui/src/lib/settings/src/components/shipping-method-list/shipping-method-list.component.ts

@@ -1,5 +1,4 @@
 import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { FormControl } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
@@ -7,21 +6,17 @@ import {
     DataService,
     DataTableService,
     GetActiveChannelQuery,
-    GetFacetListQuery,
     GetShippingMethodListQuery,
     ItemOf,
     LanguageCode,
-    ModalService,
-    NotificationService,
-    SelectionManager,
     ServerConfigService,
     ShippingMethodFilterParameter,
     ShippingMethodQuote,
     ShippingMethodSortParameter,
     TestEligibleShippingMethodsInput,
 } from '@vendure/admin-ui/core';
-import { EMPTY, merge, Observable, Subject } from 'rxjs';
-import { debounceTime, filter, switchMap, takeUntil } from 'rxjs/operators';
+import { Observable, Subject } from 'rxjs';
+import { switchMap } from 'rxjs/operators';
 
 import { TestAddress } from '../test-address-form/test-address-form.component';
 import { TestOrderLine } from '../test-order-builder/test-order-builder.component';
@@ -82,12 +77,10 @@ export class ShippingMethodListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private modalService: ModalService,
-        private notificationService: NotificationService,
-        private dataService: DataService,
-        private serverConfigService: ServerConfigService,
         router: Router,
         route: ActivatedRoute,
+        private dataService: DataService,
+        private serverConfigService: ServerConfigService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -135,35 +128,6 @@ export class ShippingMethodListComponent
         super.refreshListOnChanges(this.contentLanguage$, this.filters.valueChanges, this.sorts.valueChanges);
     }
 
-    deleteShippingMethod(id: string) {
-        this.modalService
-            .dialog({
-                title: _('catalog.confirm-delete-shipping-method'),
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(response =>
-                    response ? this.dataService.shippingMethod.deleteShippingMethod(id) : EMPTY,
-                ),
-            )
-            .subscribe(
-                () => {
-                    this.notificationService.success(_('common.notify-delete-success'), {
-                        entity: 'ShippingMethod',
-                    });
-                    this.refresh();
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'ShippingMethod',
-                    });
-                },
-            );
-    }
-
     setTestOrderLines(event: TestOrderLine[]) {
         this.testOrderLines = event;
         this.testDataUpdated = true;

+ 15 - 0
packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list-bulk-actions.ts

@@ -0,0 +1,15 @@
+import { createBulkDeleteAction, GetSellersQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { GetTaxCategoryListQuery } from '@vendure/core/e2e/graphql/generated-e2e-admin-types';
+import { map } from 'rxjs/operators';
+
+export const deleteTaxCategoriesBulkAction = createBulkDeleteAction<
+    ItemOf<GetTaxCategoryListQuery, 'taxCategories'>
+>({
+    location: 'tax-category-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.DeleteSettings) ||
+        userPermissions.includes(Permission.DeleteTaxCategory),
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.settings.deleteTaxCategories(ids).pipe(map(res => res.deleteTaxCategories)),
+});

+ 1 - 44
packages/admin-ui/src/lib/settings/src/components/tax-category-list/tax-category-list.component.ts

@@ -5,17 +5,11 @@ import {
     BaseListComponent,
     DataService,
     DataTableService,
-    DeletionResult,
     GetTaxCategoriesQuery,
     ItemOf,
-    ModalService,
-    NotificationService,
     TaxCategoryFilterParameter,
-    TaxCategoryFragment,
     TaxCategorySortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY } from 'rxjs';
-import { map, switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-tax-list',
@@ -47,11 +41,9 @@ export class TaxCategoryListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private dataService: DataService,
-        private notificationService: NotificationService,
-        private modalService: ModalService,
         route: ActivatedRoute,
         router: Router,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -78,39 +70,4 @@ export class TaxCategoryListComponent
         super.ngOnInit();
         super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
-
-    deleteTaxCategory(taxCategory: TaxCategoryFragment) {
-        return this.modalService
-            .dialog({
-                title: _('settings.confirm-delete-tax-category'),
-                body: taxCategory.name,
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(res => (res ? this.dataService.settings.deleteTaxCategory(taxCategory.id) : EMPTY)),
-                map(res => res.deleteTaxCategory),
-            )
-            .subscribe(
-                res => {
-                    if (res.result === DeletionResult.DELETED) {
-                        this.notificationService.success(_('common.notify-delete-success'), {
-                            entity: 'TaxRate',
-                        });
-                        this.refresh();
-                    } else {
-                        this.notificationService.error(res.message || _('common.notify-delete-error'), {
-                            entity: 'TaxRate',
-                        });
-                    }
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'TaxRate',
-                    });
-                },
-            );
-    }
 }

+ 12 - 0
packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list-bulk-actions.ts

@@ -0,0 +1,12 @@
+import { createBulkDeleteAction, GetTaxRateListQuery, ItemOf, Permission } from '@vendure/admin-ui/core';
+import { map } from 'rxjs/operators';
+
+export const deleteTaxRatesBulkAction = createBulkDeleteAction<ItemOf<GetTaxRateListQuery, 'taxRates'>>({
+    location: 'tax-rate-list',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.DeleteSettings) ||
+        userPermissions.includes(Permission.DeleteTaxRate),
+    getItemName: item => item.name,
+    bulkDelete: (dataService, ids) =>
+        dataService.settings.deleteTaxRates(ids).pipe(map(res => res.deleteTaxRates)),
+});

+ 1 - 43
packages/admin-ui/src/lib/settings/src/components/tax-rate-list/tax-rate-list.component.ts

@@ -5,16 +5,11 @@ import {
     BaseListComponent,
     DataService,
     DataTableService,
-    DeletionResult,
     GetTaxRateListQuery,
     ItemOf,
-    ModalService,
-    NotificationService,
     TaxRateFilterParameter,
     TaxRateSortParameter,
 } from '@vendure/admin-ui/core';
-import { EMPTY } from 'rxjs';
-import { map, switchMap } from 'rxjs/operators';
 
 @Component({
     selector: 'vdr-tax-rate-list',
@@ -59,11 +54,9 @@ export class TaxRateListComponent
         .connectToRoute(this.route);
 
     constructor(
-        private modalService: ModalService,
-        private notificationService: NotificationService,
-        private dataService: DataService,
         router: Router,
         route: ActivatedRoute,
+        private dataService: DataService,
         private dataTableService: DataTableService,
     ) {
         super(router, route);
@@ -90,39 +83,4 @@ export class TaxRateListComponent
         super.ngOnInit();
         super.refreshListOnChanges(this.filters.valueChanges, this.sorts.valueChanges);
     }
-
-    deleteTaxRate(taxRate: ItemOf<GetTaxRateListQuery, 'taxRates'>) {
-        return this.modalService
-            .dialog({
-                title: _('settings.confirm-delete-tax-rate'),
-                body: taxRate.name,
-                buttons: [
-                    { type: 'secondary', label: _('common.cancel') },
-                    { type: 'danger', label: _('common.delete'), returnValue: true },
-                ],
-            })
-            .pipe(
-                switchMap(res => (res ? this.dataService.settings.deleteTaxRate(taxRate.id) : EMPTY)),
-                map(res => res.deleteTaxRate),
-            )
-            .subscribe(
-                res => {
-                    if (res.result === DeletionResult.DELETED) {
-                        this.notificationService.success(_('common.notify-delete-success'), {
-                            entity: 'TaxRate',
-                        });
-                        this.refresh();
-                    } else {
-                        this.notificationService.error(res.message || _('common.notify-delete-error'), {
-                            entity: 'TaxRate',
-                        });
-                    }
-                },
-                err => {
-                    this.notificationService.error(_('common.notify-delete-error'), {
-                        entity: 'TaxRate',
-                    });
-                },
-            );
-    }
 }

+ 21 - 2
packages/admin-ui/src/lib/settings/src/settings.module.ts

@@ -1,13 +1,16 @@
 import { NgModule } from '@angular/core';
 import { RouterModule } from '@angular/router';
-import { SharedModule } from '@vendure/admin-ui/core';
+import { BulkActionRegistryService, SharedModule } from '@vendure/admin-ui/core';
 
 import { AddCountryToZoneDialogComponent } from './components/add-country-to-zone-dialog/add-country-to-zone-dialog.component';
 import { AdminDetailComponent } from './components/admin-detail/admin-detail.component';
+import { deleteAdministratorsBulkAction } from './components/administrator-list/administrator-list-bulk-actions';
 import { AdministratorListComponent } from './components/administrator-list/administrator-list.component';
 import { ChannelDetailComponent } from './components/channel-detail/channel-detail.component';
+import { deleteChannelsBulkAction } from './components/channel-list/channel-list-bulk-actions';
 import { ChannelListComponent } from './components/channel-list/channel-list.component';
 import { CountryDetailComponent } from './components/country-detail/country-detail.component';
+import { deleteCountriesBulkAction } from './components/country-list/country-list-bulk-actions';
 import { CountryListComponent } from './components/country-list/country-list.component';
 import { GlobalSettingsComponent } from './components/global-settings/global-settings.component';
 import { PaymentMethodDetailComponent } from './components/payment-method-detail/payment-method-detail.component';
@@ -15,16 +18,21 @@ import { PaymentMethodListComponent } from './components/payment-method-list/pay
 import { PermissionGridComponent } from './components/permission-grid/permission-grid.component';
 import { ProfileComponent } from './components/profile/profile.component';
 import { RoleDetailComponent } from './components/role-detail/role-detail.component';
+import { deleteRolesBulkAction } from './components/role-list/role-list-bulk-actions';
 import { RoleListComponent } from './components/role-list/role-list.component';
 import { SellerDetailComponent } from './components/seller-detail/seller-detail.component';
+import { deleteSellersBulkAction } from './components/seller-list/seller-list-bulk-actions';
 import { SellerListComponent } from './components/seller-list/seller-list.component';
 import { ShippingEligibilityTestResultComponent } from './components/shipping-eligibility-test-result/shipping-eligibility-test-result.component';
 import { ShippingMethodDetailComponent } from './components/shipping-method-detail/shipping-method-detail.component';
+import { deleteShippingMethodsBulkAction } from './components/shipping-method-list/shipping-method-list-bulk-actions';
 import { ShippingMethodListComponent } from './components/shipping-method-list/shipping-method-list.component';
 import { ShippingMethodTestResultComponent } from './components/shipping-method-test-result/shipping-method-test-result.component';
 import { TaxCategoryDetailComponent } from './components/tax-category-detail/tax-category-detail.component';
+import { deleteTaxCategoriesBulkAction } from './components/tax-category-list/tax-category-list-bulk-actions';
 import { TaxCategoryListComponent } from './components/tax-category-list/tax-category-list.component';
 import { TaxRateDetailComponent } from './components/tax-rate-detail/tax-rate-detail.component';
+import { deleteTaxRatesBulkAction } from './components/tax-rate-list/tax-rate-list-bulk-actions';
 import { TaxRateListComponent } from './components/tax-rate-list/tax-rate-list.component';
 import { TestAddressFormComponent } from './components/test-address-form/test-address-form.component';
 import { TestOrderBuilderComponent } from './components/test-order-builder/test-order-builder.component';
@@ -71,4 +79,15 @@ import { settingsRoutes } from './settings.routes';
         ProfileComponent,
     ],
 })
-export class SettingsModule {}
+export class SettingsModule {
+    constructor(private bulkActionRegistryService: BulkActionRegistryService) {
+        bulkActionRegistryService.registerBulkAction(deleteSellersBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteChannelsBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteAdministratorsBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteRolesBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteShippingMethodsBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteTaxCategoriesBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteTaxRatesBulkAction);
+        bulkActionRegistryService.registerBulkAction(deleteCountriesBulkAction);
+    }
+}

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Vytvořit nového administrátora",
-    "search-administrator": "Hledat podle jména / příjmení / e-mailu"
+    "create-new-administrator": "Vytvořit nového administrátora"
   },
   "asset": {
     "add-asset": "Přidat médium",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Deleting this collection will also delete all child collections",
     "confirm-delete-country": "Smazat zemi?",
     "confirm-delete-customer": "Smazat zákazníka?",
-    "confirm-delete-facet": "Smazat atribut?",
     "confirm-delete-facet-value": "Smazat hodnotu atributu?",
     "confirm-delete-product": "Smazat produkt?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Žádné zvýrazněné médium",
     "no-selection": "Žádný výběr",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Host",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } na stránku",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Jazyk",
     "launch-extension": "Spustit rozšíření",
+    "list-items-and-n-more": "",
     "live-update": "Živé aktualizace",
     "locale": "",
     "log-out": "Odhlásit",
@@ -313,6 +314,7 @@
     "update": "Aktualizovat",
     "updated-at": "Aktualizováno",
     "username": "Uživatelské jméno",
+    "value": "",
     "view-next-month": "Další měsíc",
     "view-previous-month": "Předchozí měsíc",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Výchozí daňová zóna",
     "eligible": "Způsobilé",
     "email-address": "E-mailová adresa",
+    "emailAddress": "",
     "filter-by-member-name": "Filtrovat dle země",
     "first-name": "Jméno",
     "fulfillment-handler": "Způsob zpracování",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Odebrat ze zóny",
     "roles": "Role",
     "search-by-product-name-or-sku": "Hledat dle názvu nebo SKU produktu",
-    "search-country-by-name": "Vyhledat zemi dle jména",
     "shipping-calculator": "Kalkulátor poštovného",
     "shipping-eligibility-checker": "Test způsobilosti k dodací metodě",
     "shipping-method": "Dodací metoda",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Neuen Administrator anlegen",
-    "search-administrator": "Nach Vorname / Nachname / E-Mail suchen"
+    "create-new-administrator": "Neuen Administrator anlegen"
   },
   "asset": {
     "add-asset": "Asset hinzufügen",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Wenn Sie diese Sammlung löschen, werden auch alle untergeordneten Sammlungen gelöscht.",
     "confirm-delete-country": "Land löschen?",
     "confirm-delete-customer": "Kunden löschen?",
-    "confirm-delete-facet": "Facette löschen?",
     "confirm-delete-facet-value": "Facettenwert löschen?",
     "confirm-delete-product": "Produkt löschen?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Kein \"Featured Asset\"",
     "no-selection": "Keine Auswahl",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Gast",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } pro Seite",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Sprache",
     "launch-extension": "Erweiterung starten",
+    "list-items-and-n-more": "",
     "live-update": "Live-Aktualisierung",
     "locale": "",
     "log-out": "Abmelden",
@@ -313,6 +314,7 @@
     "update": "Aktualisieren",
     "updated-at": "Aktualisiert am",
     "username": "Benutzername",
+    "value": "",
     "view-next-month": "Nächsten Monat anzeigen",
     "view-previous-month": "Vorherigen Monat anzeigen",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Standard-Steuerzone",
     "eligible": "Verfügbar",
     "email-address": "E-Mail-Adresse",
+    "emailAddress": "",
     "filter-by-member-name": "Nach Land filtern",
     "first-name": "Vorname",
     "fulfillment-handler": "Abwicklung über",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Aus Zone entfernen",
     "roles": "Rollen",
     "search-by-product-name-or-sku": "Suche nach Produktname oder Artikelnummer",
-    "search-country-by-name": "Länder nach Namen suchen",
     "shipping-calculator": "Versandkostenrechner",
     "shipping-eligibility-checker": "Verfügbarkeit der Versandart prüfen",
     "shipping-method": "Versandart",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Create new administrator",
-    "search-administrator": "Search by first name / last name / email"
+    "create-new-administrator": "Create new administrator"
   },
   "asset": {
     "add-asset": "Add asset",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Deleting this collection will also delete all child collections",
     "confirm-delete-country": "Delete country?",
     "confirm-delete-customer": "Delete customer?",
-    "confirm-delete-facet": "Delete facet?",
     "confirm-delete-facet-value": "Delete facet value?",
     "confirm-delete-product": "Delete product?",
     "confirm-delete-product-option": "Delete product option \"{name}\"?",
@@ -127,6 +125,7 @@
     "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-customers-success": "",
     "notify-bulk-delete-facets-success": "Successfully deleted {count, plural, one {1 facet} other {{count} facets}}",
     "notify-bulk-delete-products-success": "Successfully deleted {count, plural, one {1 product} other {{count} products}}",
     "notify-remove-collections-from-channel-success": "Successfully removed {count, plural, one {1 collection} other {{count} collections}} from { channelCode }",
@@ -240,12 +239,14 @@
     "force-remove": "Force remove",
     "general": "General",
     "guest": "Guest",
+    "id": "",
     "image": "Image",
     "items-per-page-option": "{ count } per page",
     "items-selected-count": "{ count } {count, plural, one {item} other {items}} selected",
     "keep-editing": "Keep editing",
     "language": "Language",
     "launch-extension": "Launch extension",
+    "list-items-and-n-more": "{ items } and {nMore} more",
     "live-update": "Live update",
     "locale": "Locale",
     "log-out": "Log out",
@@ -313,6 +314,7 @@
     "update": "Update",
     "updated-at": "Updated at",
     "username": "Username",
+    "value": "",
     "view-next-month": "View next month",
     "view-previous-month": "View previous month",
     "visibility": "Visibility",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Default tax zone",
     "eligible": "Eligible",
     "email-address": "Email address",
+    "emailAddress": "",
     "filter-by-member-name": "Filter by country",
     "first-name": "First name",
     "fulfillment-handler": "Fulfillment handler",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Remove from zone",
     "roles": "Roles",
     "search-by-product-name-or-sku": "Search by product name or SKU",
-    "search-country-by-name": "Search countries by name",
     "shipping-calculator": "Shipping calculator",
     "shipping-eligibility-checker": "Shipping eligibility checker",
     "shipping-method": "Shipping Method",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Crear nuevo administrador",
-    "search-administrator": "Buscar por nombre / apellido / correo electrónico"
+    "create-new-administrator": "Crear nuevo administrador"
   },
   "asset": {
     "add-asset": "Añadir recurso",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Eliminar esta colección también eliminará las sub-colecciones",
     "confirm-delete-country": "¿Eliminar país?",
     "confirm-delete-customer": "¿Eliminar cliente?",
-    "confirm-delete-facet": "¿Eliminar faceta?",
     "confirm-delete-facet-value": "¿Eliminar valor de faceta?",
     "confirm-delete-product": "¿Eliminar producto?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Sin recurso destacado",
     "no-selection": "Sin selección",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Invitado",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } por página",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Idioma",
     "launch-extension": "Ejecutar extensión",
+    "list-items-and-n-more": "",
     "live-update": "Actualización en vivo",
     "locale": "",
     "log-out": "Salir",
@@ -313,6 +314,7 @@
     "update": "Actualizar",
     "updated-at": "Actualizado el",
     "username": "Nombre de usuario",
+    "value": "",
     "view-next-month": "Ver próximo mes",
     "view-previous-month": "Ver mes anterior",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Zona de impuestos por defecto",
     "eligible": "Disponible",
     "email-address": "Dirección de email",
+    "emailAddress": "",
     "filter-by-member-name": "Filtrar por país",
     "first-name": "Nombre",
     "fulfillment-handler": "Gestor de ejecución de pedidos",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Eliminar de la zona",
     "roles": "Roles",
     "search-by-product-name-or-sku": "Buscar producto por nombre o código de referencia",
-    "search-country-by-name": "Buscar país por nombre",
     "shipping-calculator": "Calculador de envíos",
     "shipping-eligibility-checker": "Comprueba disponibilidad de envío",
     "shipping-method": "Método de envío",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Creer nouveau administrateur",
-    "search-administrator": "Rechercher par prénom / nom de famille / email"
+    "create-new-administrator": "Creer nouveau administrateur"
   },
   "asset": {
     "add-asset": "Ajout fichier",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Supprimer cette collection va aussi supprimer toutes les collections enfants",
     "confirm-delete-country": "Supprimer pays ?",
     "confirm-delete-customer": "Supprimer client ?",
-    "confirm-delete-facet": "Supprimer composant ?",
     "confirm-delete-facet-value": "Supprimer valeur du composant ?",
     "confirm-delete-product": "Supprimer produit ?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Pas de fichier vedette",
     "no-selection": "Pas de sélection",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Invité",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } par page",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Langue",
     "launch-extension": "Lancer extension",
+    "list-items-and-n-more": "",
     "live-update": "Mise à jour automatique",
     "locale": "",
     "log-out": "Déconnexion",
@@ -313,6 +314,7 @@
     "update": "Mettre à jour",
     "updated-at": "Mis à jour à",
     "username": "Nom d'utilisateur",
+    "value": "",
     "view-next-month": "Voir le mois suivant",
     "view-previous-month": "Voir le mois précédent",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Zone de taxe par défaut",
     "eligible": "Eligible",
     "email-address": "Adresse email",
+    "emailAddress": "",
     "filter-by-member-name": "Filtrer par pays",
     "first-name": "Prénom",
     "fulfillment-handler": "Gestionnaire de remplissage",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Retirer de la zone",
     "roles": "Roles",
     "search-by-product-name-or-sku": "Chercher par nom de produit ou par UGS",
-    "search-country-by-name": "Chercher pays par le nom",
     "shipping-calculator": "Calculateur de frais d'expédition",
     "shipping-eligibility-checker": "Controleur d'égibilité de livraison",
     "shipping-method": "Mode d'expédition",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Crea nuovo amministratore",
-    "search-administrator": "Cerca per nome / cognome / email"
+    "create-new-administrator": "Crea nuovo amministratore"
   },
   "asset": {
     "add-asset": "Aggiungi immagine",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Eliminare questa collezione rimuoverà anche le sue sotto-collezioni",
     "confirm-delete-country": "Eliminare la Nazione?",
     "confirm-delete-customer": "Eliminare questo Cliente?",
-    "confirm-delete-facet": "Eliminare l'attributo?",
     "confirm-delete-facet-value": "Eliminare il valore attributo?",
     "confirm-delete-product": "Eliminare il prodotto?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Nessun media in evidenza",
     "no-selection": "Nessuna selezione",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Ospite",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } per pagina",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Lingua",
     "launch-extension": "Lancia estensione",
+    "list-items-and-n-more": "",
     "live-update": "Aggiornamenti live",
     "locale": "",
     "log-out": "Log out",
@@ -313,6 +314,7 @@
     "update": "Aggiorna",
     "updated-at": "Aggiornare a",
     "username": "Username",
+    "value": "",
     "view-next-month": "Vedi mese successivo",
     "view-previous-month": "Vedi mese precedente",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Zona di tassazione predefinita",
     "eligible": "Compatibile",
     "email-address": "Indirizzo email",
+    "emailAddress": "",
     "filter-by-member-name": "Filtra per nazione",
     "first-name": "Nome",
     "fulfillment-handler": "Gestore spedizione",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Rimuovi dalla zona",
     "roles": "Ruoli",
     "search-by-product-name-or-sku": "Cerca per prodotto o codice SKU",
-    "search-country-by-name": "Cerca nazioni per nome",
     "shipping-calculator": "Calcolo prezzo spedizioni",
     "shipping-eligibility-checker": "Criterio di selezione metodi di spedizione",
     "shipping-method": "Metodo di spedizione",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Utwórz konto administratora",
-    "search-administrator": "Szukaj według imienia / nazwiska / adresu e-mail"
+    "create-new-administrator": "Utwórz konto administratora"
   },
   "asset": {
     "add-asset": "Dodaj zasób",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Usunięcie tej kolekcji spowoduje usunięcie także podkategorii",
     "confirm-delete-country": "Usunąć kraj?",
     "confirm-delete-customer": "",
-    "confirm-delete-facet": "Usunąć faset?",
     "confirm-delete-facet-value": "Usunąć wartość faseta?",
     "confirm-delete-product": "Usunąć produkt?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Brak polecanego zasobu",
     "no-selection": "Brak zaznaczenia",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Gość",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } na stronę",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Język",
     "launch-extension": "Uruchom rozszerzenie",
+    "list-items-and-n-more": "",
     "live-update": "Aktualizacja live",
     "locale": "",
     "log-out": "Wyloguj",
@@ -313,6 +314,7 @@
     "update": "Aktualizuj",
     "updated-at": "Zaaktualizowano dnia",
     "username": "Nazwa użytkownika",
+    "value": "",
     "view-next-month": "Wyświetl następny miesiąc",
     "view-previous-month": "Wyświetl poprzedni miesiąc",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Domyślna strefa podatkowa",
     "eligible": "Wybieralny",
     "email-address": "Email",
+    "emailAddress": "",
     "filter-by-member-name": "",
     "first-name": "Imię",
     "fulfillment-handler": "",
@@ -686,7 +689,6 @@
     "remove-from-zone": "",
     "roles": "Role",
     "search-by-product-name-or-sku": "Szukaj produktu po nazwie lub SKU",
-    "search-country-by-name": "Szukaj kraju po nazwie",
     "shipping-calculator": "Kalkulator wysyłki",
     "shipping-eligibility-checker": "Sprawdź możliwość wysyłki",
     "shipping-method": "Metoda wysyłki",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Criar novo usuário administrador",
-    "search-administrator": "Pesquisar por nome / sobrenome / e-mail"
+    "create-new-administrator": "Criar novo usuário administrador"
   },
   "asset": {
     "add-asset": "Adicionar imagens",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "A exclusão desta categoria também excluirá todas as categorias filho",
     "confirm-delete-country": "Excluir país?",
     "confirm-delete-customer": "Excluir cliente?",
-    "confirm-delete-facet": "Excluir etiqueta?",
     "confirm-delete-facet-value": "Excluir valor da etiqueta?",
     "confirm-delete-product": "Excluir produto?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Nenhum recurso em destaque",
     "no-selection": "Nenhuma seleção",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Convidado",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } por página",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Idioma",
     "launch-extension": "Iniciar extensão",
+    "list-items-and-n-more": "",
     "live-update": "Atualização ao vivo",
     "locale": "",
     "log-out": "Sair",
@@ -313,6 +314,7 @@
     "update": "Atualização",
     "updated-at": "Atualizado em",
     "username": "Nome do usuário",
+    "value": "",
     "view-next-month": "Visualizar próximo mês",
     "view-previous-month": "Visualizar mês anterior",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Zona de imposto padrão",
     "eligible": "Elegível",
     "email-address": "Email",
+    "emailAddress": "",
     "filter-by-member-name": "Filtrar por país",
     "first-name": "Nome",
     "fulfillment-handler": "Manipulador de preenchimento",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Excluir da zona",
     "roles": "Regras",
     "search-by-product-name-or-sku": "Pesquisa por nome do produto ou SKU",
-    "search-country-by-name": "Pesquisa países por nome",
     "shipping-calculator": "Calculadora de envio",
     "shipping-eligibility-checker": "Verificador de elegibilidade para envio",
     "shipping-method": "Método de envio",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Adicionar novo administrador",
-    "search-administrator": "Procurar por primeiro nome / último nome / e-mail"
+    "create-new-administrator": "Adicionar novo administrador"
   },
   "asset": {
     "add-asset": "Adicionar imagens",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Ao eliminar a categoria, todas as categorias filho serão eliminadas",
     "confirm-delete-country": "Eliminar país?",
     "confirm-delete-customer": "Eliminar cliente?",
-    "confirm-delete-facet": "Eliminar etiqueta?",
     "confirm-delete-facet-value": "Eliminar valor da etiqueta?",
     "confirm-delete-product": "Eliminar produto?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Nenhum recurso em destaque",
     "no-selection": "Nenhuma imagem seleccionada",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "Geral",
     "guest": "Convidado",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } por página",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Idioma",
     "launch-extension": "Iniciar extensão",
+    "list-items-and-n-more": "",
     "live-update": "Actualização em tempo real",
     "locale": "Localidade",
     "log-out": "Sair",
@@ -313,6 +314,7 @@
     "update": "Actualização",
     "updated-at": "Actualizado em",
     "username": "Nome do utilizador",
+    "value": "",
     "view-next-month": "Visualizar próximo mês",
     "view-previous-month": "Visualizar mês anterior",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Região de imposto padrão",
     "eligible": "Elegível",
     "email-address": "E-mail",
+    "emailAddress": "",
     "filter-by-member-name": "Filtrar por país",
     "first-name": "Nome",
     "fulfillment-handler": "Manipulador para a execução de envio",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Eliminar da região",
     "roles": "Regras",
     "search-by-product-name-or-sku": "Pesquisa por nome do produto ou SKU",
-    "search-country-by-name": "Pesquisa países por nome",
     "shipping-calculator": "Calculadora de envio",
     "shipping-eligibility-checker": "Validação da elegibilidade do método",
     "shipping-method": "Método de envio",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Создать нового администратора",
-    "search-administrator": "Поиск по имени / фамилии / электронной почте"
+    "create-new-administrator": "Создать нового администратора"
   },
   "asset": {
     "add-asset": "Добавить медиа-объект",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Удаление этой коллекции также приведет к удалению всех дочерних коллекций.",
     "confirm-delete-country": "Удалить страну?",
     "confirm-delete-customer": "Удалить клиента?",
-    "confirm-delete-facet": "Удалить тег?",
     "confirm-delete-facet-value": "Удалить значение тега?",
     "confirm-delete-product": "Удалить товар?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Нет избранного медиа-объекта",
     "no-selection": "Не выбрано",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Гость",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } на странице",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Язык",
     "launch-extension": "Запуск расширения",
+    "list-items-and-n-more": "",
     "live-update": "Обновление в режиме реального времени",
     "locale": "",
     "log-out": "Выйти",
@@ -313,6 +314,7 @@
     "update": "Обновить",
     "updated-at": "Обновлено в",
     "username": "Имя пользователя",
+    "value": "",
     "view-next-month": "Посмотреть следующий месяц",
     "view-previous-month": "Посмотреть предыдущий месяц",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Налоговая зона по умолчанию",
     "eligible": "Имеющий право",
     "email-address": "Адрес электронной почты",
+    "emailAddress": "",
     "filter-by-member-name": "Фильтровать по стране",
     "first-name": "Имя",
     "fulfillment-handler": "Обработчик выполнения",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Удалить из зоны",
     "roles": "Роли",
     "search-by-product-name-or-sku": "Поиск по названию товара или артикулу",
-    "search-country-by-name": "Поиск страны по названию",
     "shipping-calculator": "Калькулятор доставки",
     "shipping-eligibility-checker": "Контролер приемлемости доставки",
     "shipping-method": "Способ доставки",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "Створити нового адміністратора",
-    "search-administrator": "Пошук за ім'ям / прізвищем / електронною поштою"
+    "create-new-administrator": "Створити нового адміністратора"
   },
   "asset": {
     "add-asset": "Додати медіа-об'єкт",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "Видалення цієї колекції також призведе до видалення всіх дочірніх колекцій.",
     "confirm-delete-country": "Видалити країну?",
     "confirm-delete-customer": "Видалити клієнта?",
-    "confirm-delete-facet": "Видалити тег?",
     "confirm-delete-facet-value": "Видалити значення тегу?",
     "confirm-delete-product": "Видалити товар?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "Немає обраного медіа-об'єкта",
     "no-selection": "Не вибрано",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "Гість",
+    "id": "",
     "image": "",
     "items-per-page-option": "{ count } на сторінці",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "Мова",
     "launch-extension": "Запуск розширення",
+    "list-items-and-n-more": "",
     "live-update": "Оновлення в режимі реального часу",
     "locale": "",
     "log-out": "Вийти",
@@ -313,6 +314,7 @@
     "update": "Оновити",
     "updated-at": "Оновлено в",
     "username": "Ім'я користувача",
+    "value": "",
     "view-next-month": "Переглянути наступний місяць",
     "view-previous-month": "Переглянути попередній місяць",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "Податкова зона за замовчуванням",
     "eligible": "Який має право",
     "email-address": "Адреса електронної пошти",
+    "emailAddress": "",
     "filter-by-member-name": "Фільтрувати по країні",
     "first-name": "Ім'я",
     "fulfillment-handler": "Обробник виконання",
@@ -686,7 +689,6 @@
     "remove-from-zone": "Видалити із зони",
     "roles": "Ролі",
     "search-by-product-name-or-sku": "Пошук за назвою товару або артикулу",
-    "search-country-by-name": "Пошук країни за назвою",
     "shipping-calculator": "Калькулятор доставки",
     "shipping-eligibility-checker": "Контролер прийнятності доставки",
     "shipping-method": "Спосіб доставки",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "添加管理员",
-    "search-administrator": "通过名字/姓氏/电子邮件搜索"
+    "create-new-administrator": "添加管理员"
   },
   "asset": {
     "add-asset": "添加资源",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "删除这个系列会删除它所包含的子系列,确认删除码?",
     "confirm-delete-country": "确认删除国家?",
     "confirm-delete-customer": "确认删除客户吗?",
-    "confirm-delete-facet": "确认删除特征?",
     "confirm-delete-facet-value": "确认删除特征值?",
     "confirm-delete-product": "确认删除商品?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "无特征图片",
     "no-selection": "尚未选择",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "游客",
+    "id": "",
     "image": "",
     "items-per-page-option": "每页显示 { count } 条",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "语言",
     "launch-extension": "启动扩展插件",
+    "list-items-and-n-more": "",
     "live-update": "在线更新",
     "locale": "",
     "log-out": "退出",
@@ -313,6 +314,7 @@
     "update": "确认修改",
     "updated-at": "修改时间",
     "username": "用户名",
+    "value": "",
     "view-next-month": "查看下个月",
     "view-previous-month": "查看下个月",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "默认销售区域",
     "eligible": "符合条件",
     "email-address": "电子邮件",
+    "emailAddress": "",
     "filter-by-member-name": "",
     "first-name": "名",
     "fulfillment-handler": "",
@@ -686,7 +689,6 @@
     "remove-from-zone": "",
     "roles": "角色列表",
     "search-by-product-name-or-sku": "输入要搜索的产品名称或库存编码",
-    "search-country-by-name": "输入要搜索的国家名称",
     "shipping-calculator": "配送费计算",
     "shipping-eligibility-checker": "使用此配送方式的合格条件",
     "shipping-method": "配送方式",

+ 6 - 4
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -1,7 +1,6 @@
 {
   "admin": {
-    "create-new-administrator": "新增管理員",
-    "search-administrator": "透過名字/姓氏/電子郵件搜尋"
+    "create-new-administrator": "新增管理員"
   },
   "asset": {
     "add-asset": "新增檔案",
@@ -83,7 +82,6 @@
     "confirm-delete-collection-and-children-body": "移除這個系列會移除它所包含的子系列,確認移除嗎?",
     "confirm-delete-country": "確認移除此國家?",
     "confirm-delete-customer": "",
-    "confirm-delete-facet": "確認移除此特徵?",
     "confirm-delete-facet-value": "確認移除特徵值?",
     "confirm-delete-product": "確認移除商品?",
     "confirm-delete-product-option": "",
@@ -127,6 +125,7 @@
     "no-featured-asset": "並無特徵圖片",
     "no-selection": "尚未選擇",
     "notify-bulk-delete-collections-success": "",
+    "notify-bulk-delete-customers-success": "",
     "notify-bulk-delete-facets-success": "",
     "notify-bulk-delete-products-success": "",
     "notify-remove-collections-from-channel-success": "",
@@ -240,12 +239,14 @@
     "force-remove": "",
     "general": "",
     "guest": "游客",
+    "id": "",
     "image": "",
     "items-per-page-option": "每页顯示 { count } 條",
     "items-selected-count": "",
     "keep-editing": "",
     "language": "語言",
     "launch-extension": "启動扩展插件",
+    "list-items-and-n-more": "",
     "live-update": "",
     "locale": "",
     "log-out": "退出",
@@ -313,6 +314,7 @@
     "update": "確認修改",
     "updated-at": "修改時間",
     "username": "用户名",
+    "value": "",
     "view-next-month": "查看下個月",
     "view-previous-month": "查看上個月",
     "visibility": "",
@@ -668,6 +670,7 @@
     "default-tax-zone": "默認銷售區域",
     "eligible": "符合條件",
     "email-address": "電子郵件",
+    "emailAddress": "",
     "filter-by-member-name": "",
     "first-name": "名",
     "fulfillment-handler": "",
@@ -686,7 +689,6 @@
     "remove-from-zone": "",
     "roles": "角色列表",
     "search-by-product-name-or-sku": "輸入要搜索的產品名稱或庫存編碼",
-    "search-country-by-name": "輸入要搜索的國家名稱",
     "shipping-calculator": "配送費計算",
     "shipping-eligibility-checker": "使用此配送方式的合格條件",
     "shipping-method": "配送方式",