Browse Source

feat(admin-ui): Implement new collection list view

Michael Bromley 2 years ago
parent
commit
125bf51041
37 changed files with 1026 additions and 507 deletions
  1. 41 41
      packages/admin-ui/i18n-coverage.json
  2. 8 0
      packages/admin-ui/src/lib/catalog/src/catalog.module.ts
  3. 29 25
      packages/admin-ui/src/lib/catalog/src/components/collection-contents/collection-contents.component.html
  4. 0 20
      packages/admin-ui/src/lib/catalog/src/components/collection-contents/collection-contents.component.scss
  5. 139 0
      packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.html
  6. 24 0
      packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.scss
  7. 117 0
      packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.ts
  8. 14 0
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-breadcrumb.pipe.ts
  9. 42 0
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list-bulk-actions.ts
  10. 28 0
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list-common.scss
  11. 145 70
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.html
  12. 0 5
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.scss
  13. 109 96
      packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts
  14. 65 0
      packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.html
  15. 0 0
      packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.scss
  16. 85 0
      packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.ts
  17. 1 1
      packages/admin-ui/src/lib/core/src/common/base-list.component.ts
  18. 5 1
      packages/admin-ui/src/lib/core/src/common/generated-types.ts
  19. 10 2
      packages/admin-ui/src/lib/core/src/data/definitions/collection-definitions.ts
  20. 2 5
      packages/admin-ui/src/lib/core/src/data/providers/collection-data.service.ts
  21. 1 0
      packages/admin-ui/src/lib/core/src/shared/components/data-table-2/data-table2.component.scss
  22. 2 2
      packages/admin-ui/src/lib/core/src/shared/components/data-table-2/data-table2.component.ts
  23. 1 1
      packages/admin-ui/src/lib/settings/src/components/administrator-list/administrator-list.component.html
  24. 0 1
      packages/admin-ui/src/lib/settings/src/components/zone-list/zone-list.component.html
  25. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/cs.json
  26. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/de.json
  27. 14 21
      packages/admin-ui/src/lib/static/i18n-messages/en.json
  28. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/es.json
  29. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/fr.json
  30. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/it.json
  31. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/pl.json
  32. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json
  33. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json
  34. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/ru.json
  35. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/uk.json
  36. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json
  37. 12 18
      packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

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

@@ -1,71 +1,71 @@
 {
-  "generatedOn": "2023-05-01T20:16:42.501Z",
-  "lastCommit": "58dce8e9c84ba5e9050ad8aaed0c66bc256ad2d7",
+  "generatedOn": "2023-05-10T18:52:34.237Z",
+  "lastCommit": "39e22046182d30fe4359977e55175454ff82e239",
   "translationStatus": {
     "cs": {
-      "tokenCount": 712,
-      "translatedCount": 581,
-      "percentage": 82
+      "tokenCount": 706,
+      "translatedCount": 568,
+      "percentage": 80
     },
     "de": {
-      "tokenCount": 712,
-      "translatedCount": 564,
-      "percentage": 79
+      "tokenCount": 706,
+      "translatedCount": 551,
+      "percentage": 78
     },
     "en": {
-      "tokenCount": 712,
-      "translatedCount": 707,
-      "percentage": 99
+      "tokenCount": 706,
+      "translatedCount": 693,
+      "percentage": 98
     },
     "es": {
-      "tokenCount": 712,
-      "translatedCount": 610,
-      "percentage": 86
+      "tokenCount": 706,
+      "translatedCount": 596,
+      "percentage": 84
     },
     "fr": {
-      "tokenCount": 712,
-      "translatedCount": 602,
-      "percentage": 85
+      "tokenCount": 706,
+      "translatedCount": 588,
+      "percentage": 83
     },
     "it": {
-      "tokenCount": 712,
-      "translatedCount": 608,
-      "percentage": 85
+      "tokenCount": 706,
+      "translatedCount": 594,
+      "percentage": 84
     },
     "pl": {
-      "tokenCount": 712,
-      "translatedCount": 404,
-      "percentage": 57
+      "tokenCount": 706,
+      "translatedCount": 395,
+      "percentage": 56
     },
     "pt_BR": {
-      "tokenCount": 712,
-      "translatedCount": 579,
-      "percentage": 81
+      "tokenCount": 706,
+      "translatedCount": 566,
+      "percentage": 80
     },
     "pt_PT": {
-      "tokenCount": 712,
-      "translatedCount": 621,
-      "percentage": 87
+      "tokenCount": 706,
+      "translatedCount": 607,
+      "percentage": 86
     },
     "ru": {
-      "tokenCount": 712,
-      "translatedCount": 607,
-      "percentage": 85
+      "tokenCount": 706,
+      "translatedCount": 593,
+      "percentage": 84
     },
     "uk": {
-      "tokenCount": 712,
-      "translatedCount": 607,
-      "percentage": 85
+      "tokenCount": 706,
+      "translatedCount": 593,
+      "percentage": 84
     },
     "zh_Hans": {
-      "tokenCount": 712,
-      "translatedCount": 549,
-      "percentage": 77
+      "tokenCount": 706,
+      "translatedCount": 536,
+      "percentage": 76
     },
     "zh_Hant": {
-      "tokenCount": 712,
-      "translatedCount": 384,
-      "percentage": 54
+      "tokenCount": 706,
+      "translatedCount": 375,
+      "percentage": 53
     }
   }
 }

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

@@ -16,6 +16,7 @@ import { CollectionDetailComponent } from './components/collection-detail/collec
 import {
     assignCollectionsToChannelBulkAction,
     deleteCollectionsBulkAction,
+    moveCollectionsBulkAction,
     removeCollectionsFromChannelBulkAction,
 } from './components/collection-list/collection-list-bulk-actions';
 import { CollectionListComponent } from './components/collection-list/collection-list.component';
@@ -45,6 +46,9 @@ import { ProductVariantsListComponent } from './components/product-variants-list
 import { ProductVariantsTableComponent } from './components/product-variants-table/product-variants-table.component';
 import { UpdateProductOptionDialogComponent } from './components/update-product-option-dialog/update-product-option-dialog.component';
 import { VariantPriceDetailComponent } from './components/variant-price-detail/variant-price-detail.component';
+import { CollectionDataTableComponent } from './components/collection-data-table/collection-data-table.component';
+import { CollectionBreadcrumbPipe } from './components/collection-list/collection-breadcrumb.pipe';
+import { MoveCollectionsDialogComponent } from './components/move-collections-dialog/move-collections-dialog.component';
 
 const CATALOG_COMPONENTS = [
     ProductListComponent,
@@ -72,6 +76,9 @@ const CATALOG_COMPONENTS = [
     ProductOptionsEditorComponent,
     BulkAddFacetValuesDialogComponent,
     AssignToChannelDialogComponent,
+    CollectionDataTableComponent,
+    CollectionBreadcrumbPipe,
+    MoveCollectionsDialogComponent,
 ];
 
 @NgModule({
@@ -93,5 +100,6 @@ export class CatalogModule {
         bulkActionRegistryService.registerBulkAction(assignCollectionsToChannelBulkAction);
         bulkActionRegistryService.registerBulkAction(removeCollectionsFromChannelBulkAction);
         bulkActionRegistryService.registerBulkAction(deleteCollectionsBulkAction);
+        bulkActionRegistryService.registerBulkAction(moveCollectionsBulkAction);
     }
 }

+ 29 - 25
packages/admin-ui/src/lib/catalog/src/components/collection-contents/collection-contents.component.html

@@ -1,18 +1,6 @@
-<div class="contents-header">
-    <div class="header-title-row">
-        <ng-container
-            *ngTemplateOutlet="headerTemplate; context: { $implicit: contentsTotalItems$ | async }"
-        ></ng-container>
-    </div>
-    <input
-        type="text"
-        [placeholder]="'catalog.filter-by-name' | translate"
-        [formControl]="filterTermControl"
-    />
-</div>
 <div class="table-wrapper">
     <div class="progress loop" [class.visible]="isLoading"></div>
-    <vdr-data-table
+    <vdr-data-table-2
         [class.loading]="isLoading"
         [items]="contents$ | async"
         [itemsPerPage]="contentsItemsPerPage$ | async"
@@ -21,16 +9,32 @@
         (pageChange)="setContentsPageNumber($event)"
         (itemsPerPageChange)="setContentsItemsPerPage($event)"
     >
-        <ng-template let-variant="item">
-            <td class="left align-middle">{{ variant.name }}</td>
-            <td class="left align-middle"><small class="sku">{{ variant.sku }}</small></td>
-            <td class="right align-middle">
-                <vdr-table-row-action
-                    iconShape="edit"
-                    [label]="'common.edit' | translate"
-                    [linkTo]="['/catalog/products', variant.productId, { tab: 'variants' }]"
-                ></vdr-table-row-action>
-            </td>
-        </ng-template>
-    </vdr-data-table>
+        <vdr-dt2-search
+            [searchTermControl]="filterTermControl"
+            [searchTermPlaceholder]="'catalog.filter-by-name' | translate"
+        />
+        <vdr-dt2-column [heading]="'common.created-at' | translate" [hiddenByDefault]="true">
+            <ng-template let-variant="item">
+                {{ variant.createdAt | localeDate : 'short' }}
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'common.updated-at' | translate" [hiddenByDefault]="true">
+            <ng-template let-variant="item">
+                {{ variant.updatedAt | localeDate : 'short' }}
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'common.name' | translate" [optional]="false">
+            <ng-template let-variant="item">
+                <a class="button-ghost" [routerLink]="['/catalog/products', variant.productId]"
+                    ><span>{{ variant.name }}</span
+                    ><clr-icon shape="arrow right"
+                /></a>
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'catalog.sku' | translate" [optional]="false">
+            <ng-template let-variant="item">
+                {{ variant.sku }}
+            </ng-template>
+        </vdr-dt2-column>
+    </vdr-data-table-2>
 </div>

+ 0 - 20
packages/admin-ui/src/lib/catalog/src/components/collection-contents/collection-contents.component.scss

@@ -1,23 +1,3 @@
-
-.contents-header {
-    background-color: var(--color-component-bg-100);
-    position: sticky;
-    top: 0;
-    padding: 6px;
-    z-index: 1;
-    border-bottom: 1px solid var(--color-component-border-200);
-
-    .header-title-row {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-    }
-
-    .clr-input {
-        width: 100%;
-    }
-}
-
 :host {
     display: block;
     ::ng-deep table {

+ 139 - 0
packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.html

@@ -0,0 +1,139 @@
+<div class="bulk-actions">
+    <ng-content select="vdr-bulk-action-menu"></ng-content>
+</div>
+<table class="" [class.no-select]="disableSelect" [style.table-layout]="!items?.length ? 'fixed' : 'inherit'">
+    <thead [class.items-selected]="selectionManager?.selection.length">
+        <tr class="heading-row">
+            <th *ngIf="selectionManager" class="align-middle">
+                <input
+                    type="checkbox"
+                    clrCheckbox
+                    [checked]="selectionManager?.areAllCurrentItemsSelected()"
+                    (change)="onToggleAllClick()"
+                />
+            </th>
+            <th *ngFor="let column of visibleColumns; last as isLast" [class.expand]="column.expand">
+                <div class="cell-content" [ngClass]="column.align">
+                    <span>{{ column.heading }}</span>
+                    <div *ngIf="column.sort as sort" class="sort-toggle">
+                        <button (click)="sort.toggleSortOrder()" [class.active]="sort.sortOrder">
+                            <clr-icon *ngIf="!sort.sortOrder" shape="two-way-arrows left"></clr-icon>
+                            <clr-icon *ngIf="sort.sortOrder === 'ASC'" shape="arrow up"></clr-icon>
+                            <clr-icon *ngIf="sort.sortOrder === 'DESC'" shape="arrow down"></clr-icon>
+                        </button>
+                        <div class="sort-label" *ngIf="sort.sortOrder">{{ sort.sortOrder }}</div>
+                    </div>
+                </div>
+
+                <div *ngIf="isLast" class="column-picker">
+                    <vdr-data-table-colum-picker [columns]="columns?.toArray()"></vdr-data-table-colum-picker>
+                </div>
+            </th>
+        </tr>
+        <tr *ngIf="searchComponent || customSearchTemplate || filters?.length">
+            <th [attr.colspan]="visibleColumns.length + (selectionManager ? 1 : 0)" class="filter-row">
+                <!--<div class="search-wrapper">
+                    <clr-icon shape="search" class="search-icon"></clr-icon>
+                    <input [formControl]="searchTermControl" [placeholder]="searchTermPlaceholder" />
+                </div>-->
+                <ng-container *ngTemplateOutlet="searchComponent?.template"></ng-container>
+                <ng-container *ngTemplateOutlet="customSearchTemplate"></ng-container>
+                <ng-container *ngIf="filters">
+                    <div class="filters">
+                        <vdr-data-table-filters
+                            *ngFor="let activeFilter of filters.activeFilters"
+                            [filterWithValue]="activeFilter"
+                            [filters]="filters"
+                            class="mt-1"
+                        ></vdr-data-table-filters>
+                        <vdr-data-table-filters
+                            *ngIf="filters.length"
+                            [filters]="filters"
+                            class="mt-1"
+                        ></vdr-data-table-filters>
+                    </div>
+                </ng-container>
+            </th>
+        </tr>
+    </thead>
+    <tbody
+        cdkDropList
+        cdkDropListLockAxis="y"
+        (cdkDropListDropped)="onDrop($event)"
+        [cdkDropListSortPredicate]="sortPredicate"
+    >
+        <ng-container
+            *ngFor="
+                let item of items
+                    | paginate
+                        : {
+                              itemsPerPage: itemsPerPage,
+                              currentPage: currentPage,
+                              totalItems: totalItems,
+                              id: id,
+                          };
+                index as i;
+                trackBy: trackByFn
+            "
+        >
+            <ng-container
+                [ngTemplateOutlet]="collectionRowTmp"
+                [ngTemplateOutletContext]="{ item: item, i: i, depth: 0 }"
+            ></ng-container>
+        </ng-container>
+        <ng-container>
+            <tr *ngIf="!items?.length">
+                <td [attr.colspan]="visibleColumns.length + (selectionManager ? 1 : 0)">
+                    <vdr-empty-placeholder [emptyStateLabel]="emptyStateLabel"></vdr-empty-placeholder>
+                </td>
+            </tr>
+        </ng-container>
+    </tbody>
+</table>
+<div class="table-footer ml-4">
+    <vdr-items-per-page-controls
+        *ngIf="totalItems"
+        [itemsPerPage]="itemsPerPage"
+        (itemsPerPageChange)="itemsPerPageChange.emit($event)"
+    ></vdr-items-per-page-controls>
+    <div *ngIf="totalItems" class="p5">
+        {{ 'common.total-items' | translate : { currentStart, currentEnd, totalItems } }}
+    </div>
+
+    <vdr-pagination-controls
+        *ngIf="totalItems"
+        [id]="id"
+        [currentPage]="currentPage"
+        [itemsPerPage]="itemsPerPage"
+        [totalItems]="totalItems"
+        (pageChange)="pageChange.emit($event)"
+    ></vdr-pagination-controls>
+</div>
+
+<ng-template #collectionRowTmp let-item="item" let-i="i" let-depth="depth">
+    <tr #collectionRow cdkDrag [cdkDragData]="{ depth: depth, collection: item }" cdkDragBoundary="tbody">
+        <td *ngIf="selectionManager" class="selection-col" [class.active]="activeIndex === i">
+            <div class="drag-handle" cdkDragHandle [title]="'catalog.reorder-collection' | translate">
+                <clr-icon shape="drag-handle"></clr-icon>
+            </div>
+            <input
+                type="checkbox"
+                clrCheckbox
+                [checked]="selectionManager?.isSelected(item)"
+                (click)="onRowClick(item, $event)"
+            />
+        </td>
+        <td *ngFor="let column of visibleColumns" [class.active]="activeIndex === i">
+            <div class="cell-content" [ngClass]="column.align">
+                <ng-container
+                    *ngTemplateOutlet="column.template; context: { item: item, index: i, depth: depth }"
+                ></ng-container>
+            </div>
+        </td>
+    </tr>
+    <ng-container *ngFor="let subCollection of getSubcollections(item); index as j">
+        <ng-container
+            *ngTemplateOutlet="collectionRowTmp; context: { item: subCollection, i: i + j, depth: depth + 1 }"
+        ></ng-container>
+    </ng-container>
+</ng-template>

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

@@ -0,0 +1,24 @@
+.selection-col {
+    display: flex;
+}
+.drag-handle {
+    cursor: grab;
+}
+
+/* Animate items as they're being sorted. */
+.cdk-drop-list-dragging .cdk-drag {
+  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+/* Animate an item that has been dropped. */
+.cdk-drag-animating {
+  transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.cdk-drag-preview {
+    opacity: 0;
+}
+
+.cdk-drag-placeholder {
+    background-color: var(--color-primary-100) !important;
+}

+ 117 - 0
packages/admin-ui/src/lib/catalog/src/components/collection-data-table/collection-data-table.component.ts

@@ -0,0 +1,117 @@
+import { CdkDrag, CdkDragDrop, CdkDropList, DragDrop, DragRef } from '@angular/cdk/drag-drop';
+import {
+    AfterViewInit,
+    ChangeDetectionStrategy,
+    ChangeDetectorRef,
+    Component,
+    EventEmitter,
+    Input,
+    OnInit,
+    Output,
+    QueryList,
+    ViewChild,
+    ViewChildren,
+} from '@angular/core';
+import {
+    DataTable2Component,
+    GetCollectionListQuery,
+    ItemOf,
+    LocalStorageService,
+} from '@vendure/admin-ui/core';
+
+export type CollectionTableItem = ItemOf<GetCollectionListQuery, 'collections'>;
+export type CollectionOrderEvent = {
+    collectionId: string;
+    parentId: string;
+    index: number;
+};
+@Component({
+    selector: 'vdr-collection-data-table',
+    templateUrl: './collection-data-table.component.html',
+    styleUrls: [
+        '../../../../core/src/shared/components/data-table-2/data-table2.component.scss',
+        './collection-data-table.component.scss',
+    ],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class CollectionDataTableComponent
+    extends DataTable2Component<CollectionTableItem>
+    implements OnInit, AfterViewInit
+{
+    @Input() subCollections: CollectionTableItem[];
+    @Output() changeOrder = new EventEmitter<CollectionOrderEvent>();
+    @ViewChild(CdkDropList, { static: true }) dropList: CdkDropList<{
+        depth: number;
+        collection: CollectionTableItem;
+    }>;
+    @ViewChildren('collectionRow', { read: CdkDrag }) collectionRowList: QueryList<CdkDrag>;
+    dragRefs: DragRef[] = [];
+    constructor(
+        protected changeDetectorRef: ChangeDetectorRef,
+        protected localStorageService: LocalStorageService,
+        private dragDrop: DragDrop,
+    ) {
+        super(changeDetectorRef, localStorageService);
+    }
+
+    ngOnInit() {
+        super.ngOnInit();
+    }
+
+    ngAfterViewInit() {
+        this.collectionRowList.changes.subscribe((val: QueryList<CdkDrag>) => {
+            this.dropList.getSortedItems().forEach(item => this.dropList.removeItem(item));
+            for (const ref of val.toArray()) {
+                ref.dropContainer = this.dropList;
+                ref._dragRef._withDropContainer(this.dropList._dropListRef);
+                this.dropList.addItem(ref);
+            }
+        });
+    }
+
+    getSubcollections(item: CollectionTableItem) {
+        return this.subCollections?.filter(c => c.parentId === item.id);
+    }
+
+    /**
+     * Predicate function that only allows even numbers to be
+     * sorted into even indices and odd numbers at odd indices.
+     */
+    sortPredicate = (index: number, item: CdkDrag<{ depth: number; collection: CollectionTableItem }>) => {
+        const itemAtIndex = this.dropList.getSortedItems()[index];
+        return itemAtIndex?.data.collection.parentId === item.data.collection.parentId;
+    };
+
+    onDrop(
+        event: CdkDragDrop<{
+            depth: number;
+            collection: CollectionTableItem;
+        }>,
+    ) {
+        const isTopLevel = event.item.data.collection.breadcrumbs.length === 2;
+        const pageIndexOffset = isTopLevel ? (this.currentPage - 1) * this.itemsPerPage : 0;
+        const parentId = event.item.data.collection.parentId;
+        const parentIndex = this.items.findIndex(i => i.id === parentId);
+        const adjustedIndex = pageIndexOffset + event.currentIndex - parentIndex - 1;
+        this.changeOrder.emit({
+            collectionId: event.item.data.collection.id,
+            index: adjustedIndex,
+            parentId: event.item.data.collection.parentId,
+        });
+
+        if (isTopLevel) {
+            this.items = [...this.items];
+            this.items.splice(event.previousIndex, 1);
+            this.items.splice(event.currentIndex, 0, event.item.data.collection);
+        } else {
+            const parent = this.items.find(i => i.id === parentId);
+            if (parent) {
+                const subCollections = this.getSubcollections(parent);
+                const adjustedPreviousIndex = pageIndexOffset + event.previousIndex - parentIndex - 1;
+                subCollections.splice(adjustedPreviousIndex, 1);
+                subCollections.splice(event.currentIndex, 0, event.item.data.collection);
+            }
+        }
+        this.changeDetectorRef.markForCheck();
+    }
+}

+ 14 - 0
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-breadcrumb.pipe.ts

@@ -0,0 +1,14 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { GetCollectionListQuery, ItemOf } from '@vendure/admin-ui/core';
+
+/**
+ * Removes the root collection and self breadcrumb from the collection breadcrumb list.
+ */
+@Pipe({
+    name: 'collectionBreadcrumb',
+})
+export class CollectionBreadcrumbPipe implements PipeTransform {
+    transform(value: ItemOf<GetCollectionListQuery, 'collections'>): unknown {
+        return value?.breadcrumbs.slice(1, -1);
+    }
+}

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

@@ -7,6 +7,7 @@ import {
     getChannelCodeFromUserStatus,
     isMultiChannel,
     ModalService,
+    MoveCollectionInput,
     NotificationService,
     Permission,
 } from '@vendure/admin-ui/core';
@@ -16,6 +17,7 @@ import { mapTo, switchMap } from 'rxjs/operators';
 
 import { AssignToChannelDialogComponent } from '../assign-to-channel-dialog/assign-to-channel-dialog.component';
 import { CollectionPartial } from '../collection-tree/collection-tree.types';
+import { MoveCollectionsDialogComponent } from '../move-collections-dialog/move-collections-dialog.component';
 
 import { CollectionListComponent } from './collection-list.component';
 
@@ -74,6 +76,46 @@ export const deleteCollectionsBulkAction: BulkAction<CollectionPartial, Collecti
     },
 };
 
+export const moveCollectionsBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {
+    location: 'collection-list',
+    label: _('catalog.move-collections'),
+    icon: 'layers',
+    requiresPermission: userPermissions =>
+        userPermissions.includes(Permission.UpdateCatalog) ||
+        userPermissions.includes(Permission.UpdateProduct),
+    onClick: ({ injector, selection, hostComponent, clearSelection }) => {
+        const modalService = injector.get(ModalService);
+        const dataService = injector.get(DataService);
+        const notificationService = injector.get(NotificationService);
+        modalService
+            .fromComponent(MoveCollectionsDialogComponent, {
+                size: 'xl',
+                closable: true,
+            })
+            .pipe(
+                switchMap(result => {
+                    if (result) {
+                        const inputs: MoveCollectionInput[] = selection.map(c => ({
+                            collectionId: c.id,
+                            parentId: result.id,
+                            index: 0,
+                        }));
+                        return dataService.collection.moveCollection(inputs);
+                    } else {
+                        return EMPTY;
+                    }
+                }),
+            )
+            .subscribe(result => {
+                notificationService.success(_('catalog.move-collections-success'), {
+                    count: selection.length,
+                });
+                clearSelection();
+                hostComponent.refresh();
+            });
+    },
+};
+
 export const assignCollectionsToChannelBulkAction: BulkAction<CollectionPartial, CollectionListComponent> = {
     location: 'collection-list',
     label: _('catalog.assign-to-channel'),

+ 28 - 0
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list-common.scss

@@ -0,0 +1,28 @@
+:host {
+    --indent-spacing: 18px;
+}
+.indent-1 {
+    padding-left: var(--indent-spacing);
+}
+.indent-2 {
+    padding-left: calc(var(--indent-spacing) * 2);
+}
+.indent-3 {
+    padding-left: calc(var(--indent-spacing) * 3);
+}
+.indent-4, .indent-5, .indent-6, .indent-7, .indent-8, .indent-9 {
+    padding-left: calc(var(--indent-spacing) * 4);
+}
+.child-arrow {
+    margin: 1px 6px;
+    &.transparent {
+        opacity: 0;
+    }
+}
+.breadcrumb {
+    display: flex;
+}
+.separator {
+    color: var(--color-weight-500);
+    margin: 0 3px;
+}

+ 145 - 70
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.html

@@ -1,32 +1,5 @@
-<vdr-action-bar>
-    <vdr-ab-left>
-        <div class="">
-            <input
-                type="text"
-                name="searchTerm"
-                [formControl]="filterTermControl"
-                [placeholder]="'catalog.filter-by-name' | translate"
-                class="clr-input search-input"
-            />
-            <div class="flex center">
-                <clr-toggle-wrapper
-                    class="expand-all-toggle mt-2"
-                >
-                    <input type="checkbox" clrToggle [(ngModel)]="expandAll" (change)="toggleExpandAll()" />
-                    <label>
-                        {{ 'catalog.expand-all-collections' | translate }}
-                    </label>
-                </clr-toggle-wrapper>
-                <vdr-language-selector
-                    class="mt-2"
-                    [availableLanguageCodes]="availableLanguages$ | async"
-                    [currentLanguageCode]="contentLanguage$ | async"
-                    (languageCodeChange)="setLanguage($event)"
-                ></vdr-language-selector>
-            </div>
-        </div>
-    </vdr-ab-left>
-    <vdr-ab-right>
+<vdr-page-header>
+    <vdr-page-title>
         <vdr-action-bar-items locationId="collection-list"></vdr-action-bar-items>
         <a
             class="btn btn-primary"
@@ -36,45 +9,147 @@
             <clr-icon shape="plus"></clr-icon>
             {{ 'catalog.create-new-collection' | translate }}
         </a>
-    </vdr-ab-right>
-</vdr-action-bar>
-<div class="bulk-select-controls">
-    <input
-        type="checkbox"
-        clrCheckbox
-        [checked]="selectionManager.areAllCurrentItemsSelected()"
-        (click)="selectionManager.toggleSelectAll()"
-    />
-    <vdr-bulk-action-menu
-        class="ml2"
-        locationId="collection-list"
-        [hostComponent]="this"
-        [selectionManager]="selectionManager"
-    ></vdr-bulk-action-menu>
-</div>
-<div class="collection-wrapper">
-    <vdr-collection-tree
-        [collections]="items$ | async"
-        [activeCollectionId]="activeCollectionId$ | async"
-        [expandAll]="expandAll"
-        [expandedIds]="expandedIds"
-        [selectionManager]="selectionManager"
-        (rearrange)="onRearrange($event)"
-        (deleteCollection)="deleteCollection($event)"
-    ></vdr-collection-tree>
-
-    <div class="collection-contents" [class.expanded]="activeCollectionId$ | async">
-        <vdr-collection-contents [collectionId]="activeCollectionId$ | async">
-            <ng-template let-count>
-                <div class="collection-title">
-                    {{ activeCollectionTitle$ | async }} ({{
-                        'common.results-count' | translate: { count: count }
-                    }})
-                </div>
-                <button type="button" class="close-button" (click)="closeContents()">
-                    <clr-icon shape="close"></clr-icon>
-                </button>
-            </ng-template>
-        </vdr-collection-contents>
+    </vdr-page-title>
+</vdr-page-header>
+<vdr-page-body>
+    <div class="flex center mt-2 mr-4" *ngIf="(availableLanguages$ | async)?.length > 1">
+        <vdr-language-selector
+            class="mt-2"
+            [availableLanguageCodes]="availableLanguages$ | async"
+            [currentLanguageCode]="contentLanguage$ | async"
+            (languageCodeChange)="setLanguage($event)"
+        ></vdr-language-selector>
     </div>
-</div>
+    <vdr-split-view [rightPanelOpen]="activeCollectionId$ | async" (closeClicked)="closeContents()">
+        <ng-template vdrSplitViewLeft>
+            <vdr-collection-data-table
+                class="mt-2"
+                id="collection-list"
+                [items]="items$ | async"
+                [subCollections]="subCollections$ | async"
+                [itemsPerPage]="itemsPerPage$ | async"
+                [totalItems]="totalItems$ | async"
+                [currentPage]="currentPage$ | async"
+                [filters]="filters"
+                [activeIndex]="activeCollectionIndex$ | async"
+                (pageChange)="setPageNumber($event)"
+                (itemsPerPageChange)="setItemsPerPage($event)"
+                (changeOrder)="onRearrange($event)"
+            >
+                <vdr-bulk-action-menu
+                    locationId="collection-list"
+                    [hostComponent]="this"
+                    [selectionManager]="selectionManager"
+                ></vdr-bulk-action-menu>
+                <vdr-dt2-search
+                    [searchTermControl]="searchTermControl"
+                    [searchTermPlaceholder]="'common.search-by-name' | translate"
+                ></vdr-dt2-search>
+                <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+                    <ng-template let-collection="item">
+                        {{ collection.id }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    [heading]="'common.created-at' | translate"
+                    [hiddenByDefault]="true"
+                    [sort]="sorts.get('createdAt')"
+                >
+                    <ng-template let-collection="item">
+                        {{ collection.createdAt | localeDate : 'short' }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    [heading]="'common.updated-at' | translate"
+                    [hiddenByDefault]="true"
+                    [sort]="sorts.get('updatedAt')"
+                >
+                    <ng-template let-collection="item">
+                        {{ collection.updatedAt | localeDate : 'short' }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    [heading]="'common.position' | translate"
+                    [hiddenByDefault]="true"
+                    [sort]="sorts.get('position')"
+                >
+                    <ng-template let-collection="item">
+                        {{ collection.position }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    [heading]="'common.name' | translate"
+                    [optional]="false"
+                    [sort]="sorts.get('name')"
+                >
+                    <ng-template let-collection="item" let-depth="depth">
+                        <div [ngClass]="'indent-' + depth"></div>
+                        <clr-icon
+                            class="child-arrow"
+                            [class.transparent]="depth === 0"
+                            shape="child-arrow"
+                            *ngIf="!collection.children?.length"
+                        ></clr-icon>
+                        <button
+                            class="icon-button folder-button"
+                            *ngIf="collection.children?.length"
+                            (click)="toggleExpanded(collection)"
+                        >
+                            <clr-icon
+                                shape="folder"
+                                *ngIf="!expandedIds.includes(collection.id)"
+                            ></clr-icon>
+                            <clr-icon
+                                shape="folder-open"
+                                *ngIf="expandedIds.includes(collection.id)"
+                            ></clr-icon>
+                        </button>
+                        <a class="button-ghost" [routerLink]="['./', collection.id]"
+                            ><span>{{ collection.name }}</span>
+                            <clr-icon shape="arrow right"></clr-icon>
+                        </a>
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column [heading]="'common.breadcrumb' | translate">
+                    <ng-template let-collection="item">
+                        <div class="breadcrumb">
+                            <ng-container *ngIf="collection | collectionBreadcrumb as breadcrumbs">
+                                <ng-container *ngIf="breadcrumbs.length">
+                                    <div *ngFor="let item of breadcrumbs">
+                                        <span class="separator">/</span>{{ item.name }}
+                                    </div>
+                                </ng-container>
+                                <span class="separator" *ngIf="!breadcrumbs.length">/</span>
+                            </ng-container>
+                        </div>
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column [heading]="'common.slug' | translate" [sort]="sorts.get('slug')">
+                    <ng-template let-collection="item">
+                        {{ collection.slug }}
+                    </ng-template>
+                </vdr-dt2-column>
+                <vdr-dt2-column
+                    [heading]="'common.view-contents' | translate"
+                    [optional]="false"
+                >
+                    <ng-template let-collection="item">
+                        <a
+                            class="button-small bg-weight-150"
+                            [routerLink]="['./', { contents: collection.id }]"
+                            queryParamsHandling="preserve"
+                        >
+                            <span>{{ 'common.view-contents' | translate }}</span>
+                            <clr-icon shape="file-group"></clr-icon>
+                        </a>
+                    </ng-template>
+                </vdr-dt2-column>
+            </vdr-collection-data-table>
+        </ng-template>
+        <ng-template vdrSplitViewRight [splitViewTitle]="activeCollectionTitle$ | async">
+            <ng-container *ngIf="activeCollectionId$ | async as activeGroup">
+                <vdr-collection-contents [collectionId]="activeCollectionId$ | async"></vdr-collection-contents>
+            </ng-container>
+        </ng-template>
+    </vdr-split-view>
+</vdr-page-body>

+ 0 - 5
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.scss

@@ -12,11 +12,6 @@
     align-items: center;
     border-bottom: 1px solid var(--color-component-border-200);
 }
-
-.expand-all-toggle {
-    display: block;
-}
-
 .collection-wrapper {
     display: flex;
     height: calc(100% - 50px);

+ 109 - 96
packages/admin-ui/src/lib/catalog/src/components/collection-list/collection-list.component.ts

@@ -1,81 +1,127 @@
-import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
-import { UntypedFormControl } from '@angular/forms';
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core';
 import { ActivatedRoute, Router } from '@angular/router';
 import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
 import {
+    BaseListComponent,
+    CollectionFilterParameter,
+    CollectionSortParameter,
     DataService,
+    DataTableService,
     GetCollectionListQuery,
     ItemOf,
     LanguageCode,
     ModalService,
     NotificationService,
-    QueryResult,
-    SelectionManager,
     ServerConfigService,
 } from '@vendure/admin-ui/core';
-import { combineLatest, EMPTY, Observable, Subject } from 'rxjs';
-import {
-    debounceTime,
-    distinctUntilChanged,
-    map,
-    shareReplay,
-    switchMap,
-    take,
-    takeUntil,
-    tap,
-} from 'rxjs/operators';
-
-import { CollectionPartial, RearrangeEvent } from '../collection-tree/collection-tree.types';
+import { combineLatest, EMPTY, Observable, of } from 'rxjs';
+import { distinctUntilChanged, map, switchMap, take, takeUntil, tap } from 'rxjs/operators';
+import { CollectionOrderEvent } from '../collection-data-table/collection-data-table.component';
 
 @Component({
     selector: 'vdr-collection-list',
     templateUrl: './collection-list.component.html',
-    styleUrls: ['./collection-list.component.scss'],
+    styleUrls: ['./collection-list.component.scss', './collection-list-common.scss'],
     changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class CollectionListComponent implements OnInit, OnDestroy {
-    filterTermControl = new UntypedFormControl('');
+export class CollectionListComponent
+    extends BaseListComponent<GetCollectionListQuery, ItemOf<GetCollectionListQuery, 'collections'>>
+    implements OnInit
+{
     activeCollectionId$: Observable<string | null>;
+    activeCollectionIndex$: Observable<number>;
     activeCollectionTitle$: Observable<string>;
-    items$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;
+    subCollections$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;
     availableLanguages$: Observable<LanguageCode[]>;
     contentLanguage$: Observable<LanguageCode>;
-    expandAll = false;
     expandedIds: string[] = [];
-    selectionManager: SelectionManager<CollectionPartial>;
-    private queryResult: QueryResult<any>;
-    private destroy$ = new Subject<void>();
+
+    readonly filters = this.dataTableService
+        .createFilterCollection<CollectionFilterParameter>()
+        .addDateFilters()
+        .addFilter({
+            name: 'slug',
+            label: _('common.slug'),
+            type: { kind: 'text' },
+            filterField: 'slug',
+        })
+        .connectToRoute(this.route);
+
+    readonly sorts = this.dataTableService
+        .createSortCollection<CollectionSortParameter>()
+        .defaultSort('position', 'ASC')
+        .addSort({ name: 'createdAt' })
+        .addSort({ name: 'updatedAt' })
+        .addSort({ name: 'name' })
+        .addSort({ name: 'slug' })
+        .addSort({ name: 'position' })
+        .connectToRoute(this.route);
 
     constructor(
         private dataService: DataService,
         private notificationService: NotificationService,
         private modalService: ModalService,
-        private router: Router,
-        private route: ActivatedRoute,
+        router: Router,
+        route: ActivatedRoute,
         private serverConfigService: ServerConfigService,
         private changeDetectorRef: ChangeDetectorRef,
+        private dataTableService: DataTableService,
     ) {
-        this.selectionManager = new SelectionManager({
-            additiveMode: true,
-            multiSelect: true,
-            itemsAreEqual: (a, b) => a.id === b.id,
-        });
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) => this.dataService.collection.getCollections().refetchOnChannelChange(),
+            data => data.collections,
+            (skip, _take) => {
+                const topLevelOnly =
+                    this.searchTermControl.value === '' && this.filters.activeFilters.length === 0
+                        ? true
+                        : undefined;
+                return {
+                    options: {
+                        skip,
+                        take: _take,
+                        filter: {
+                            name: { contains: this.searchTermControl.value },
+                            ...this.filters.createFilterInput(),
+                        },
+                        topLevelOnly,
+                        sort: this.sorts.createSortInput(),
+                    },
+                };
+            },
+        );
     }
 
     ngOnInit() {
-        this.queryResult = this.dataService.collection.getCollections(1000, 0).refetchOnChannelChange();
-        this.items$ = this.queryResult
-            .mapStream(data => data.collections.items)
-            .pipe(
-                tap(items => this.selectionManager.setCurrentItems(items)),
-                shareReplay(1),
-            );
+        super.ngOnInit();
         this.activeCollectionId$ = this.route.paramMap.pipe(
             map(pm => pm.get('contents')),
             distinctUntilChanged(),
         );
-        this.expandedIds = this.route.snapshot.queryParamMap.get('expanded')?.split(',') ?? [];
-        this.expandAll = this.route.snapshot.queryParamMap.get('expanded') === 'all';
+        const expandedIds$ = this.route.queryParamMap.pipe(
+            map(qpm => qpm.get('expanded')),
+            distinctUntilChanged(),
+            map(ids => (ids ? ids.split(',') : [])),
+        );
+        expandedIds$.pipe(takeUntil(this.destroy$)).subscribe(ids => {
+            this.expandedIds = ids;
+        });
+        this.subCollections$ = combineLatest(expandedIds$, this.refresh$).pipe(
+            switchMap(([ids]) => {
+                if (ids.length) {
+                    return this.dataService.collection
+                        .getCollections({
+                            take: 999,
+                            filter: {
+                                parentId: { in: ids },
+                            },
+                        })
+                        .mapStream(data => data.collections.items);
+                } else {
+                    return of([]);
+                }
+            }),
+        );
 
         this.activeCollectionTitle$ = combineLatest(this.activeCollectionId$, this.items$).pipe(
             map(([id, collections]) => {
@@ -86,51 +132,19 @@ export class CollectionListComponent implements OnInit, OnDestroy {
                 return '';
             }),
         );
+        this.activeCollectionIndex$ = combineLatest(this.activeCollectionId$, this.items$).pipe(
+            map(([id, collections]) => (id ? collections.findIndex(c => c.id === id) : -1)),
+        );
         this.availableLanguages$ = this.serverConfigService.getAvailableLanguages();
         this.contentLanguage$ = this.dataService.client
             .uiState()
             .mapStream(({ uiState }) => uiState.contentLanguage)
             .pipe(tap(() => this.refresh()));
 
-        this.filterTermControl.valueChanges
-            .pipe(debounceTime(250), takeUntil(this.destroy$))
-            .subscribe(term => {
-                this.router.navigate(['./'], {
-                    queryParams: {
-                        q: term || undefined,
-                    },
-                    queryParamsHandling: 'merge',
-                    relativeTo: this.route,
-                });
-            });
-
-        this.route.queryParamMap
-            .pipe(
-                map(qpm => qpm.get('q')),
-                distinctUntilChanged(),
-                takeUntil(this.destroy$),
-            )
-            .subscribe(() => this.refresh());
-        this.filterTermControl.patchValue(this.route.snapshot.queryParamMap.get('q'));
-    }
-
-    ngOnDestroy() {
-        this.queryResult.completed$.next();
-        this.destroy$.next(undefined);
-        this.destroy$.complete();
+        super.refreshListOnChanges(this.contentLanguage$, this.filters.valueChanges, this.sorts.valueChanges);
     }
 
-    toggleExpandAll() {
-        this.router.navigate(['./'], {
-            queryParams: {
-                expanded: this.expandAll ? 'all' : undefined,
-            },
-            queryParamsHandling: 'merge',
-            relativeTo: this.route,
-        });
-    }
-
-    onRearrange(event: RearrangeEvent) {
+    onRearrange(event: CollectionOrderEvent) {
         this.dataService.collection.moveCollection([event]).subscribe({
             next: () => {
                 this.notificationService.success(_('common.notify-saved-changes'));
@@ -146,8 +160,9 @@ export class CollectionListComponent implements OnInit, OnDestroy {
         this.items$
             .pipe(
                 take(1),
-                map(items => -1 < items.findIndex(i => i.parent && i.parent.id === id)),
-                switchMap(hasChildren => this.modalService.dialog({
+                map(items => -1 < items.findIndex(i => i.parentId === id)),
+                switchMap(hasChildren =>
+                    this.modalService.dialog({
                         title: _('catalog.confirm-delete-collection'),
                         body: hasChildren
                             ? _('catalog.confirm-delete-collection-and-children-body')
@@ -156,7 +171,8 @@ export class CollectionListComponent implements OnInit, OnDestroy {
                             { type: 'secondary', label: _('common.cancel') },
                             { type: 'danger', label: _('common.delete'), returnValue: true },
                         ],
-                    })),
+                    }),
+                ),
                 switchMap(response => (response ? this.dataService.collection.deleteCollection(id) : EMPTY)),
             )
             .subscribe(
@@ -184,22 +200,19 @@ export class CollectionListComponent implements OnInit, OnDestroy {
         this.dataService.client.setContentLanguage(code).subscribe();
     }
 
-    refresh() {
-        const filterTerm = this.route.snapshot.queryParamMap.get('q');
-        this.queryResult.ref.refetch({
-            options: {
-                skip: 0,
-                take: 1000,
-                ...(filterTerm
-                    ? {
-                          filter: {
-                              name: {
-                                  contains: filterTerm,
-                              },
-                          },
-                      }
-                    : {}),
+    toggleExpanded(collection: ItemOf<GetCollectionListQuery, 'collections'>) {
+        let expandedIds = this.expandedIds;
+        if (!expandedIds.includes(collection.id)) {
+            expandedIds.push(collection.id);
+        } else {
+            expandedIds = expandedIds.filter(id => id !== collection.id);
+        }
+        this.router.navigate(['./'], {
+            queryParams: {
+                expanded: expandedIds.filter(id => !!id).join(','),
             },
+            queryParamsHandling: 'merge',
+            relativeTo: this.route,
         });
     }
 }

+ 65 - 0
packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.html

@@ -0,0 +1,65 @@
+<ng-template vdrDialogTitle>
+    {{ 'catalog.move-collections' | translate }}
+</ng-template>
+<vdr-collection-data-table
+    class="mt-2"
+    id="move-collection-list"
+    [items]="items$ | async"
+    [subCollections]="subCollections$ | async"
+    [itemsPerPage]="itemsPerPage$ | async"
+    [totalItems]="totalItems$ | async"
+    [currentPage]="currentPage$ | async"
+    (pageChange)="currentPage$.next($event)"
+    (itemsPerPageChange)="itemsPerPage$.next($event)"
+>
+    <vdr-dt2-search
+        [searchTermControl]="searchTermControl"
+        [searchTermPlaceholder]="'common.search-by-name' | translate"
+    ></vdr-dt2-search>
+    <vdr-dt2-column [heading]="'common.id' | translate" [hiddenByDefault]="true">
+        <ng-template let-collection="item">
+            {{ collection.id }}
+        </ng-template>
+    </vdr-dt2-column>
+    <vdr-dt2-column [heading]="'common.name' | translate" [optional]="false">
+        <ng-template let-collection="item" let-depth="depth">
+            <div [ngClass]="'indent-' + depth"></div>
+            <clr-icon
+                class="child-arrow"
+                [class.transparent]="depth === 0"
+                shape="child-arrow"
+                *ngIf="!collection.children?.length"
+            ></clr-icon>
+            <button
+                class="icon-button folder-button"
+                *ngIf="collection.children?.length"
+                (click)="toggleExpanded(collection)"
+            >
+                <clr-icon shape="folder" *ngIf="!expandedIds.includes(collection.id)"></clr-icon>
+                <clr-icon shape="folder-open" *ngIf="expandedIds.includes(collection.id)"></clr-icon>
+            </button>
+            <button class="button-ghost" (click)="resolveWith(collection)">
+                <span>{{ 'catalog.move-collection-to' | translate : { name: collection.name } }}</span>
+            </button>
+        </ng-template>
+    </vdr-dt2-column>
+    <vdr-dt2-column [heading]="'common.breadcrumb' | translate">
+        <ng-template let-collection="item">
+            <div class="breadcrumb">
+                <ng-container *ngIf="collection | collectionBreadcrumb as breadcrumbs">
+                    <ng-container *ngIf="breadcrumbs.length">
+                        <div *ngFor="let item of breadcrumbs">
+                            <span class="separator">/</span>{{ item.name }}
+                        </div>
+                    </ng-container>
+                    <span class="separator" *ngIf="!breadcrumbs.length">/</span>
+                </ng-container>
+            </div>
+        </ng-template>
+    </vdr-dt2-column>
+    <vdr-dt2-column [heading]="'common.slug' | translate">
+        <ng-template let-collection="item">
+            {{ collection.slug }}
+        </ng-template>
+    </vdr-dt2-column>
+</vdr-collection-data-table>

+ 0 - 0
packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.scss


+ 85 - 0
packages/admin-ui/src/lib/catalog/src/components/move-collections-dialog/move-collections-dialog.component.ts

@@ -0,0 +1,85 @@
+import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { DataService, Dialog, GetCollectionListQuery, ItemOf } from '@vendure/admin-ui/core';
+import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
+import { debounceTime, distinctUntilChanged, startWith, switchMap, tap } from 'rxjs/operators';
+
+@Component({
+    selector: 'vdr-move-collections-dialog',
+    templateUrl: './move-collections-dialog.component.html',
+    styleUrls: ['./move-collections-dialog.component.scss', '../collection-list/collection-list-common.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MoveCollectionsDialogComponent
+    implements OnInit, Dialog<ItemOf<GetCollectionListQuery, 'collections'>>
+{
+    resolveWith: (result?: ItemOf<GetCollectionListQuery, 'collections'>) => void;
+    searchTermControl = new FormControl('');
+    items$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;
+    totalItems$: Observable<number>;
+    currentPage$ = new BehaviorSubject(1);
+    itemsPerPage$ = new BehaviorSubject(10);
+    expandedIds$ = new Subject<string[]>();
+    expandedIds: string[] = [];
+    subCollections$: Observable<Array<ItemOf<GetCollectionListQuery, 'collections'>>>;
+
+    constructor(private dataService: DataService) {}
+
+    ngOnInit() {
+        const getCollectionsResult = this.dataService.collection.getCollections();
+
+        const searchTerm$ = this.searchTermControl.valueChanges.pipe(
+            debounceTime(250),
+            distinctUntilChanged(),
+            startWith(''),
+        );
+        const currentPage$ = this.currentPage$.pipe(distinctUntilChanged());
+        const itemsPerPage$ = this.itemsPerPage$.pipe(distinctUntilChanged());
+        combineLatest(searchTerm$, currentPage$, itemsPerPage$).subscribe(
+            ([searchTerm, currentPage, itemsPerPage]) => {
+                const topLevelOnly = searchTerm === '';
+                getCollectionsResult.ref.refetch({
+                    options: {
+                        skip: (currentPage - 1) * itemsPerPage,
+                        take: itemsPerPage,
+                        filter: {
+                            name: { contains: searchTerm },
+                        },
+                        topLevelOnly,
+                    },
+                });
+            },
+        );
+
+        this.items$ = getCollectionsResult.mapStream(data => data.collections.items);
+        this.totalItems$ = getCollectionsResult.mapStream(data => data.collections.totalItems);
+
+        this.subCollections$ = this.expandedIds$.pipe(
+            tap(val => (this.expandedIds = val)),
+            switchMap(ids => {
+                if (ids.length) {
+                    return this.dataService.collection
+                        .getCollections({
+                            take: 999,
+                            filter: {
+                                parentId: { in: ids },
+                            },
+                        })
+                        .mapStream(data => data.collections.items);
+                } else {
+                    return of([]);
+                }
+            }),
+        );
+    }
+
+    toggleExpanded(collection: ItemOf<GetCollectionListQuery, 'collections'>) {
+        let expandedIds = this.expandedIds;
+        if (!expandedIds.includes(collection.id)) {
+            expandedIds.push(collection.id);
+        } else {
+            expandedIds = expandedIds.filter(id => id !== collection.id);
+        }
+        this.expandedIds$.next(expandedIds);
+    }
+}

+ 1 - 1
packages/admin-ui/src/lib/core/src/common/base-list.component.ts

@@ -110,7 +110,7 @@ export class BaseListComponent<ResultType, ItemType, VariableType extends Record
     private mappingFn: MappingFn<ItemType, ResultType>;
     private onPageChangeFn: OnPageChangeFn<VariableType> = (skip, take) =>
         ({ options: { skip, take } } as any);
-    private refresh$ = new BehaviorSubject<undefined>(undefined);
+    protected refresh$ = new BehaviorSubject<undefined>(undefined);
     private defaults: { take: number; skip: number } = { take: 10, skip: 0 };
 
     constructor(protected router: Router, protected route: ActivatedRoute) {}

+ 5 - 1
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -434,6 +434,7 @@ export type Collection = Node & {
   languageCode?: Maybe<LanguageCode>;
   name: Scalars['String'];
   parent?: Maybe<Collection>;
+  parentId: Scalars['ID'];
   position: Scalars['Int'];
   productVariants: ProductVariantList;
   slug: Scalars['String'];
@@ -461,6 +462,7 @@ export type CollectionFilterParameter = {
   isPrivate?: InputMaybe<BooleanOperators>;
   languageCode?: InputMaybe<StringOperators>;
   name?: InputMaybe<StringOperators>;
+  parentId?: InputMaybe<IdOperators>;
   position?: InputMaybe<NumberOperators>;
   slug?: InputMaybe<StringOperators>;
   updatedAt?: InputMaybe<DateOperators>;
@@ -483,6 +485,7 @@ export type CollectionListOptions = {
   sort?: InputMaybe<CollectionSortParameter>;
   /** Takes n results, for use in pagination */
   take?: InputMaybe<Scalars['Int']>;
+  topLevelOnly?: InputMaybe<Scalars['Boolean']>;
 };
 
 /**
@@ -500,6 +503,7 @@ export type CollectionSortParameter = {
   description?: InputMaybe<SortOrder>;
   id?: InputMaybe<SortOrder>;
   name?: InputMaybe<SortOrder>;
+  parentId?: InputMaybe<SortOrder>;
   position?: InputMaybe<SortOrder>;
   slug?: InputMaybe<SortOrder>;
   updatedAt?: InputMaybe<SortOrder>;
@@ -6630,7 +6634,7 @@ export type GetCollectionListQueryVariables = Exact<{
 }>;
 
 
-export type GetCollectionListQuery = { collections: { __typename?: 'CollectionList', totalItems: number, items: Array<{ __typename?: 'Collection', id: string, name: string, slug: string, description: string, isPrivate: boolean, featuredAsset?: { __typename?: 'Asset', id: string, createdAt: any, updatedAt: any, name: string, fileSize: number, mimeType: string, type: AssetType, preview: string, source: string, width: number, height: number, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null, parent?: { __typename?: 'Collection', id: string } | null }> } };
+export type GetCollectionListQuery = { collections: { __typename?: 'CollectionList', totalItems: number, items: Array<{ __typename?: 'Collection', id: string, createdAt: any, updatedAt: any, name: string, slug: string, position: number, isPrivate: boolean, parentId: string, breadcrumbs: Array<{ __typename?: 'CollectionBreadcrumb', id: string, name: string, slug: string }>, featuredAsset?: { __typename?: 'Asset', id: string, createdAt: any, updatedAt: any, name: string, fileSize: number, mimeType: string, type: AssetType, preview: string, source: string, width: number, height: number, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null, children?: Array<{ __typename?: 'Collection', id: string }> | null }> } };
 
 export type GetCollectionQueryVariables = Exact<{
   id: Scalars['ID'];

+ 10 - 2
packages/admin-ui/src/lib/core/src/data/definitions/collection-definitions.ts

@@ -62,14 +62,22 @@ export const GET_COLLECTION_LIST = gql`
         collections(options: $options) {
             items {
                 id
+                createdAt
+                updatedAt
                 name
                 slug
-                description
+                position
                 isPrivate
+                breadcrumbs {
+                    id
+                    name
+                    slug
+                }
                 featuredAsset {
                     ...Asset
                 }
-                parent {
+                parentId
+                children {
                     id
                 }
             }

+ 2 - 5
packages/admin-ui/src/lib/core/src/data/providers/collection-data.service.ts

@@ -27,15 +27,12 @@ export class CollectionDataService {
         return this.baseDataService.query<Codegen.GetCollectionFiltersQuery>(GET_COLLECTION_FILTERS);
     }
 
-    getCollections(take: number = 10, skip: number = 0) {
+    getCollections(options?: Codegen.CollectionListOptions) {
         return this.baseDataService.query<
             Codegen.GetCollectionListQuery,
             Codegen.GetCollectionListQueryVariables
         >(GET_COLLECTION_LIST, {
-            options: {
-                take,
-                skip,
-            },
+            options,
         });
     }
 

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

@@ -83,6 +83,7 @@ table.no-select {
 th,
 td {
     padding: calc(var(--space-unit) * 1) calc(var(--space-unit) * 1);
+    font-size: var(--font-size-sm);
 }
 
 tr td:first-of-type,

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

@@ -117,8 +117,8 @@ export class DataTable2Component<T> implements AfterContentInit, OnChanges, OnIn
     private subscription: Subscription | undefined;
 
     constructor(
-        private changeDetectorRef: ChangeDetectorRef,
-        private localStorageService: LocalStorageService,
+        protected changeDetectorRef: ChangeDetectorRef,
+        protected localStorageService: LocalStorageService,
     ) {}
 
     get selectionManager() {

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

@@ -63,7 +63,7 @@
                 </a>
             </ng-template>
         </vdr-dt2-column>
-        <vdr-dt2-column [heading]="'settings.emailAddress' | translate" [sort]="sorts.get('emailAddress')">
+        <vdr-dt2-column [heading]="'settings.email-address' | translate" [sort]="sorts.get('emailAddress')">
             <ng-template let-administrator="item">
                 {{ administrator.emailAddress }}
             </ng-template>

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

@@ -79,7 +79,6 @@
                 <vdr-dt2-column
                     [heading]="'common.view-contents' | translate"
                     [optional]="false"
-                    [sort]="sorts.get('name')"
                 >
                     <ng-template let-customerGroup="item">
                         <a

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Náhled ceny v kanálu",
     "collection-contents": "Obsah kolekce",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Smazat administrátora?",
     "confirm-delete-assets": "Smazat {count} {count, plural, one {médium} few {média} other {médií}}?",
-    "confirm-delete-channel": "Smazat kanál?",
     "confirm-delete-collection": "Smazat kolekci?",
     "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-value": "Smazat hodnotu atributu?",
     "confirm-delete-product": "Smazat produkt?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Smazat variantu produktu?",
-    "confirm-delete-promotion": "Smazat propagaci?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Smazat dopravní metodu?",
-    "confirm-delete-zone": "Smazat zónu?",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Rozevřít všechny kolekce",
     "facet-value-not-available": "",
     "facet-values": "Hodnoty atributů",
     "filter-by-name": "Filtrovat dle jména",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Správa variant",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Posunout dolů",
     "move-to": "Posunout",
     "move-up": "Posunout nahoru",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Produkt se nepovedlo odebrat z kanálu",
@@ -158,6 +153,7 @@
     "remove-option": "Odebrat volbu",
     "remove-product-from-channel": "Odebrat produkt z kanálu",
     "remove-product-variant-from-channel": "Odebrat variantu z kanálu",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Zrušit",
     "cancel-navigation": "Zrušit navigaci",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Heslo",
+    "position": "",
     "price": "Cena",
     "price-with-tax": "Cena s daní",
     "private": "Soukromé",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Odebrat položku ze seznamu",
     "results-count": "{ count } {count, plural, one {výsledek} other {výsledků/y}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Vybrat...",
     "select-display-language": "Vyberte jazyk",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "",
@@ -315,6 +315,7 @@
     "updated-at": "Aktualizováno",
     "username": "Uživatelské jméno",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Další měsíc",
     "view-previous-month": "Předchozí měsíc",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Adresy",
     "city": "Město",
     "company": "",
-    "confirm-delete-customer-group": "Delete customer group?",
     "confirm-remove-customer-from-group": "Remove customer from group?",
     "country": "Země",
     "create-customer-group": "Create customer group",
@@ -376,7 +376,6 @@
     "registered": "Registrován",
     "remove-customers-from-group-success": "Odebrán: {customerCount, plural, one {1 zákazník} other {{customerCount} zákazníci/zákazníků}} z \"{ groupName }\"",
     "remove-from-group": "Odebrat ze skupiny",
-    "search-by-group-name": "Hledat výraz",
     "search-customers-by-email": "Hledat podle e-mailové adresy",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Přidat produkty do testovací objednávky",
     "channel": "Kanál",
     "channel-token": "Token kanálu",
-    "confirm-delete-payment-method": "",
-    "confirm-delete-role": "Smazat roli?",
-    "confirm-delete-tax-category": "Smazat daňovou kategorii?",
-    "confirm-delete-tax-rate": "Smazat daňovou sazbu?",
     "create-new-channel": "Vytvořit kanál",
     "create-new-country": "Vytvořit zemi",
     "create-new-payment-method": "",
@@ -671,7 +666,6 @@
     "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í",
     "global-out-of-stock-threshold": "Globální prahová hodnota pro vyprodání zásob",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Kanal-Preisvorschau",
     "collection-contents": "Inhalt der Sammlung",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Administrator löschen?",
     "confirm-delete-assets": "{count} {count, plural, one {Asset} other {Assets}} löschen?",
-    "confirm-delete-channel": "Kanal löschen?",
     "confirm-delete-collection": "Sammlung löschen?",
     "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-value": "Facettenwert löschen?",
     "confirm-delete-product": "Produkt löschen?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Produktvariante löschen?",
-    "confirm-delete-promotion": "Werbeaktion löschen?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Versandart löschen?",
-    "confirm-delete-zone": "Zone löschen?",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Alle Sammlungen erweitern",
     "facet-value-not-available": "",
     "facet-values": "Facettenwerte",
     "filter-by-name": "Nach Name filtern",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Varianten verwalten",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Nach unten bewegen",
     "move-to": "Verschieben nach",
     "move-up": "Nach oben bewegen",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Das Produkt konnte nicht aus dem Kanal entfernt werden",
@@ -158,6 +153,7 @@
     "remove-option": "Option entfernen",
     "remove-product-from-channel": "Produkt aus dem Kanal entfernen",
     "remove-product-variant-from-channel": "",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Abbrechen",
     "cancel-navigation": "Navigation abbrechen",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Passwort",
+    "position": "",
     "price": "Preis",
     "price-with-tax": "Preis mit Steuer",
     "private": "Privat",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Artikel von Liste entfernen",
     "results-count": "{ count } {count, plural, one {Ergebnis} other {Ergebnisse}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Auswählen...",
     "select-display-language": "Anzeigesprache wählen",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Tags",
@@ -315,6 +315,7 @@
     "updated-at": "Aktualisiert am",
     "username": "Benutzername",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Nächsten Monat anzeigen",
     "view-previous-month": "Vorherigen Monat anzeigen",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Adressen",
     "city": "Stadt",
     "company": "",
-    "confirm-delete-customer-group": "Kundengruppe löschen?",
     "confirm-remove-customer-from-group": "Von Kundengruppe entfernen?",
     "country": "Land",
     "create-customer-group": "Kundengruppe anlegen",
@@ -376,7 +376,6 @@
     "registered": "Registriert",
     "remove-customers-from-group-success": "{customerCount, plural, one {Kunde} other {{customerCount} Kunden}} aus \"{ groupName }\" entfernt",
     "remove-from-group": "Aus dieser Gruppe entfernen",
-    "search-by-group-name": "Suche nach Begriff",
     "search-customers-by-email": "Suche nach E-Mail-Adresse",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Kunde auswählen",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Produkte zur Testbestellung hinzufügen",
     "channel": "Kanal",
     "channel-token": "Kanal-Token",
-    "confirm-delete-payment-method": "",
-    "confirm-delete-role": "Rolle löschen?",
-    "confirm-delete-tax-category": "Steuerkategorie löschen?",
-    "confirm-delete-tax-rate": "Steuersatz löschen?",
     "create-new-channel": "Neuen Kanal erstellen",
     "create-new-country": "Neues Land erstellen",
     "create-new-payment-method": "Neue Zahlungsmethode erstellen",
@@ -671,7 +666,6 @@
     "eligible": "Verfügbar",
     "email-address": "E-Mail-Adresse",
     "emailAddress": "",
-    "filter-by-member-name": "Nach Land filtern",
     "first-name": "Vorname",
     "fulfillment-handler": "Abwicklung über",
     "global-out-of-stock-threshold": "Globale ausverkauft-Grenze",

+ 14 - 21
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Channel price preview",
     "collection-contents": "Collection contents",
     "collection-slug": "Collection slug",
+    "confirm-bulk-delete": "Delete multiple items?",
     "confirm-bulk-delete-collections": "Delete {count} collections?",
-    "confirm-bulk-delete-facets": "Delete {count} facets?",
     "confirm-bulk-delete-products": "Delete {count} products?",
     "confirm-cancel": "Cancel?",
     "confirm-delete-administrator": "Delete administrator?",
     "confirm-delete-assets": "Delete {count} {count, plural, one {asset} other {assets}}?",
-    "confirm-delete-channel": "Delete channel?",
     "confirm-delete-collection": "Delete collection?",
     "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-value": "Delete facet value?",
     "confirm-delete-product": "Delete product?",
     "confirm-delete-product-option": "Delete product option \"{name}\"?",
     "confirm-delete-product-option-group": "Delete product option group \"{name}\"?",
     "confirm-delete-product-variant": "Delete product variant \"{name}\"?",
-    "confirm-delete-promotion": "Delete promotion?",
-    "confirm-delete-seller": "Delete seller?",
-    "confirm-delete-shipping-method": "Delete shipping method?",
-    "confirm-delete-zone": "Delete zone?",
     "confirm-deletion-of-unused-variants-body": "The following product variants have been made obsolete due to the addition of new options. They will be deleted during the creation of the new product variants.",
     "confirm-deletion-of-unused-variants-title": "Delete obsolete product variants?",
     "create-draft-order": "Create draft order",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Please ensure all SKUs are unique",
     "edit-facet-values": "Edit facet values",
     "edit-options": "Edit options",
-    "expand-all-collections": "Expand all collections",
     "facet-value-not-available": "Facet value \"{ id }\" not available",
     "facet-values": "Facet values",
     "filter-by-name": "Filter by name",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "Inherit filters from parent",
     "live-preview-contents": "Live-preview contents",
     "manage-variants": "Manage variants",
+    "move-collection-to": "Move to { name }",
+    "move-collections": "Move collections",
+    "move-collections-success": "Moved {count, plural, one {1 collection} other {{count} collections}}",
     "move-down": "Move down",
     "move-to": "Move to",
     "move-up": "Move up",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "Could not delete {count, plural, one {1 item} other {{count} items}}",
+    "notify-delete-success-with-count": "Successfully deleted {count, plural, one {1 item} other {{count} items}}",
     "notify-remove-collections-from-channel-success": "Successfully removed {count, plural, one {1 collection} other {{count} collections}} from { channelCode }",
     "notify-remove-facets-from-channel-success": "Successfully removed {count, plural, one {1 facet} other {{count} facets}} from { channelCode }",
     "notify-remove-product-from-channel-error": "Could not remove product from channel",
@@ -158,6 +153,7 @@
     "remove-option": "Remove option",
     "remove-product-from-channel": "Remove product from channel",
     "remove-product-variant-from-channel": "Remove product variant from channel",
+    "reorder-collection": "Re-order collection",
     "root-collection": "Root collection",
     "run-pending-search-index-updates": "Run {count, plural, one {1 pending update} other {{count} pending updates}}",
     "running-search-index-updates": "Running {count, plural, one {1 update} other {{count} updates}} to search index",
@@ -203,6 +199,7 @@
     "boolean-false": "false",
     "boolean-or": "or",
     "boolean-true": "true",
+    "breadcrumb": "Breadcrumb",
     "browser-default": "Browser default",
     "cancel": "Cancel",
     "cancel-navigation": "Cancel navigation",
@@ -239,7 +236,7 @@
     "force-remove": "Force remove",
     "general": "General",
     "guest": "Guest",
-    "id": "",
+    "id": "ID",
     "image": "Image",
     "items-per-page-option": "{ count } per page",
     "items-selected-count": "{ count } {count, plural, one {item} other {items}} selected",
@@ -284,6 +281,7 @@
     "operator-notContains": "does not contain",
     "operator-regex": "matches regex",
     "password": "Password",
+    "position": "Position",
     "price": "Price",
     "price-with-tax": "Price with tax",
     "private": "Private",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Remove item from list",
     "results-count": "{ count } {count, plural, one {result} other {results}}",
     "sample-formatting": "Sample formatting",
+    "search-by-name": "Search by name",
     "select": "Select...",
     "select-display-language": "Select display language",
     "select-items-with-count": "Select { count } {count, plural, one {item} other {items}}",
@@ -304,6 +303,7 @@
     "seller": "Seller",
     "set-language": "Set language",
     "short-date": "Short date",
+    "slug": "Slug",
     "start-date": "Start date",
     "status": "Status",
     "tags": "Tags",
@@ -314,7 +314,8 @@
     "update": "Update",
     "updated-at": "Updated at",
     "username": "Username",
-    "value": "",
+    "value": "Value",
+    "view-contents": "View contents",
     "view-next-month": "View next month",
     "view-previous-month": "View previous month",
     "visibility": "Visibility",
@@ -330,7 +331,6 @@
     "addresses": "Addresses",
     "city": "City",
     "company": "Company",
-    "confirm-delete-customer-group": "Delete customer group?",
     "confirm-remove-customer-from-group": "Remove customer from group?",
     "country": "Country",
     "create-customer-group": "Create customer group",
@@ -376,7 +376,6 @@
     "registered": "Registered",
     "remove-customers-from-group-success": "Removed {customerCount, plural, one {1 customer} other {{customerCount} customers}} from \"{ groupName }\"",
     "remove-from-group": "Remove from this group",
-    "search-by-group-name": "Search by group name",
     "search-customers-by-email": "Search by email address",
     "search-customers-by-email-last-name-postal-code": "Search by email / last name / postal code",
     "select-customer": "Select customer",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Add products to the test order",
     "channel": "Channel",
     "channel-token": "Channel token",
-    "confirm-delete-payment-method": "Delete payment method?",
-    "confirm-delete-role": "Delete role?",
-    "confirm-delete-tax-category": "Delete tax category?",
-    "confirm-delete-tax-rate": "Delete tax rate?",
     "create-new-channel": "Create new channel",
     "create-new-country": "Create new country",
     "create-new-payment-method": "Create new payment method",
@@ -670,8 +665,6 @@
     "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",
     "global-out-of-stock-threshold": "Global out-of-stock threshold",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Vista previa de precio para el canal de ventas",
     "collection-contents": "Contenidos de la colección",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "¿Eliminar administrador?",
     "confirm-delete-assets": "¿Eliminar recurso?",
-    "confirm-delete-channel": "¿Eliminar canal de ventas?",
     "confirm-delete-collection": "¿Eliminar colección?",
     "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-value": "¿Eliminar valor de faceta?",
     "confirm-delete-product": "¿Eliminar producto?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "¿Eliminar variante?",
-    "confirm-delete-promotion": "¿Eliminar promoción?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "¿Eliminar método de envío?",
-    "confirm-delete-zone": "¿Eliminar zona?",
     "confirm-deletion-of-unused-variants-body": "Las siguientes variantes de producto han quedado obsoletas debido a la incorporación de nuevas opciones. Se eliminarán durante la creación de las nuevas variantes de producto.",
     "confirm-deletion-of-unused-variants-title": "¿Eliminar variantes de producto obsoletas?",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Por favor, asegúrese de que todos los códigos de referencia son únicos",
     "edit-facet-values": "",
     "edit-options": "Editar opciones",
-    "expand-all-collections": "Expandir todas las colecciones",
     "facet-value-not-available": "",
     "facet-values": "Valores de faceta",
     "filter-by-name": "Filtrar por nombre",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Gestionar variantes",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Mover abajo",
     "move-to": "Mover a",
     "move-up": "Mover arriba",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "No fue posible eliminar el producto del canal",
@@ -158,6 +153,7 @@
     "remove-option": "Eliminar opción",
     "remove-product-from-channel": "Eliminar producto del canal de ventas",
     "remove-product-variant-from-channel": "Eliminar variante de producto del canal de ventas ",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Cancelar",
     "cancel-navigation": "Cancelar navegación",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Contraseña",
+    "position": "",
     "price": "Precio",
     "price-with-tax": "Precio (impuesto incluido)",
     "private": "Privado",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Eliminar elemento de la lista",
     "results-count": "{ count } {count, plural, one {resultado} other {resultados}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Seleccionar...",
     "select-display-language": "Seleccionar idioma de interfaz",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Etiquetas",
@@ -315,6 +315,7 @@
     "updated-at": "Actualizado el",
     "username": "Nombre de usuario",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Ver próximo mes",
     "view-previous-month": "Ver mes anterior",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Direcciones",
     "city": "Ciudad",
     "company": "",
-    "confirm-delete-customer-group": "¿Eliminar grupo de clientes?",
     "confirm-remove-customer-from-group": "¿Eliminar cliente del grupo?",
     "country": "País",
     "create-customer-group": "Crear grupo de clientes",
@@ -376,7 +376,6 @@
     "registered": "Registrado",
     "remove-customers-from-group-success": "{customerCount, plural, one {1 cliente} other {{customerCount} clientes}} {customerCount, plural, one {eliminado} other {eliminados}} de \"{ groupName }\"",
     "remove-from-group": "Eliminar del grupo",
-    "search-by-group-name": "Buscar por término",
     "search-customers-by-email": "Buscar por correo electrónico",
     "search-customers-by-email-last-name-postal-code": "Buscar por apellido / correo electrónico / Código postal",
     "select-customer": "Seleccionar cliente",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Añade productos al pedido de pruebas",
     "channel": "Canal de ventas",
     "channel-token": "Token de canal",
-    "confirm-delete-payment-method": "¿Eliminar método de pago?",
-    "confirm-delete-role": "¿Eliminar rol?",
-    "confirm-delete-tax-category": "¿Eliminar categoría de impuestos?",
-    "confirm-delete-tax-rate": "¿Eliminar tasa de impuestos?",
     "create-new-channel": "Crear nuevo canal de ventas",
     "create-new-country": "Crear nuevo país",
     "create-new-payment-method": "Crear nuevo método de pago",
@@ -671,7 +666,6 @@
     "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",
     "global-out-of-stock-threshold": "Límite agotamiento de existencias",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/fr.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Prévisualisation du prix du canal",
     "collection-contents": "Contenu de la Collection",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Supprimer administrateur?",
     "confirm-delete-assets": "Supprimer {count} {count, plural, one {fichier} other {fichiers}} ?",
-    "confirm-delete-channel": "Supprimer canal ?",
     "confirm-delete-collection": "Supprimer collection ?",
     "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-value": "Supprimer valeur du composant ?",
     "confirm-delete-product": "Supprimer produit ?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Supprimer variation du produit ?",
-    "confirm-delete-promotion": "Supprimer promotion ?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Supprimer mode d'expédition ?",
-    "confirm-delete-zone": "Supprimer zone ?",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Etendre toutes les collections",
     "facet-value-not-available": "",
     "facet-values": "Valeurs de composant",
     "filter-by-name": "Filtrer par nom",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Gérer les variations",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Déplacer vers le bas",
     "move-to": "Déplacer à",
     "move-up": "Déplacer vers le haut",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Retrait du produit du canal échoué",
@@ -158,6 +153,7 @@
     "remove-option": "Retirer l'option",
     "remove-product-from-channel": "Retirer le produit du canal",
     "remove-product-variant-from-channel": "Retirer la variante du produit du canal",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Annuler",
     "cancel-navigation": "Annuler la navigation",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Mot de passe",
+    "position": "",
     "price": "Prix",
     "price-with-tax": "Prix avec taxe",
     "private": "Privé",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Retirer l'article de la liste",
     "results-count": "{ count } {count, plural, one {resultat} other {resultats}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Selectionner...",
     "select-display-language": "Choisir la langue d'affichage",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Mots-clés",
@@ -315,6 +315,7 @@
     "updated-at": "Mis à jour à",
     "username": "Nom d'utilisateur",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Voir le mois suivant",
     "view-previous-month": "Voir le mois précédent",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Adresses",
     "city": "Ville",
     "company": "",
-    "confirm-delete-customer-group": "Supprimer le groupe de clients ?",
     "confirm-remove-customer-from-group": "Retirer le client du groupe ?",
     "country": "Pays",
     "create-customer-group": "Creer le groupe de clients",
@@ -376,7 +376,6 @@
     "registered": "Inscrit",
     "remove-customers-from-group-success": "Retrait {customerCount, plural, one {d'un client} other {de {customerCount} clients}} de \"{ groupName }\"",
     "remove-from-group": "Retirer de ce groupe",
-    "search-by-group-name": "Chercher le terme",
     "search-customers-by-email": "Chercher par adresse email",
     "search-customers-by-email-last-name-postal-code": "Rechercher par nom / adresse email / code postal",
     "select-customer": "Sélectionner client",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Ajouter des produits à la commande de test",
     "channel": "Canal",
     "channel-token": "Jeton de canal",
-    "confirm-delete-payment-method": "Supprimer méthode de paiement ?",
-    "confirm-delete-role": "Supprimer le role ?",
-    "confirm-delete-tax-category": "Supprimer la catégorie de taxe ?",
-    "confirm-delete-tax-rate": "Supprimer le taux de taxe ?",
     "create-new-channel": "Créer nouveau canal",
     "create-new-country": "Créer nouveau pays",
     "create-new-payment-method": "Créer une nouvelle méthode de paiement",
@@ -671,7 +666,6 @@
     "eligible": "Eligible",
     "email-address": "Adresse email",
     "emailAddress": "",
-    "filter-by-member-name": "Filtrer par pays",
     "first-name": "Prénom",
     "fulfillment-handler": "Gestionnaire de remplissage",
     "global-out-of-stock-threshold": "Limite de rupture de stock globale",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/it.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Anteprima prezzo canale",
     "collection-contents": "Contenuti della Collezione",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Eliminare l'amministratore?",
     "confirm-delete-assets": "Eliminare {count} {count, plural, one {media} other {media}}?",
-    "confirm-delete-channel": "Eliminare il canale?",
     "confirm-delete-collection": "Eliminare la collezione?",
     "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-value": "Eliminare il valore attributo?",
     "confirm-delete-product": "Eliminare il prodotto?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Eliminare la variante?",
-    "confirm-delete-promotion": "Eliminare la promozione?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Eliminare il metodo di spedizione?",
-    "confirm-delete-zone": "Eliminare la zona?",
     "confirm-deletion-of-unused-variants-body": "Le seguenti varianti sono diventate obsolete a seguito dell'aggiunta di nuove opzioni. Queste verranno cancellate durante la creazione delle nuove varianti.",
     "confirm-deletion-of-unused-variants-title": "Cancellare le varianti obsolete?",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Per favore assicurati che tutte le SKU siano univoche",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Espandi le collezioni",
     "facet-value-not-available": "",
     "facet-values": "Valori attributo",
     "filter-by-name": "Filtra per nome",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Gestione varianti",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Sposta in basso",
     "move-to": "Sposta in",
     "move-up": "Sposta in alto",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Impossibile rimuovere il prodotto dal canale",
@@ -158,6 +153,7 @@
     "remove-option": "Rimuovi opzione",
     "remove-product-from-channel": "Rimuovi prodotto dal canale",
     "remove-product-variant-from-channel": "Rimuovi variante dal canale",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Annulla",
     "cancel-navigation": "Annulla navigazione",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Password",
+    "position": "",
     "price": "Prezzo",
     "price-with-tax": "Prezzo tasse incluse",
     "private": "Privato",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Rimuovi elemento dalla lista",
     "results-count": "{ count } {count, plural, one {risultato} other {risultati}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Seleziona...",
     "select-display-language": "Seleziona lingua",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Tag",
@@ -315,6 +315,7 @@
     "updated-at": "Aggiornare a",
     "username": "Username",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Vedi mese successivo",
     "view-previous-month": "Vedi mese precedente",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Indirizzi",
     "city": "Città",
     "company": "",
-    "confirm-delete-customer-group": "Eliminare gruppo di clienti?",
     "confirm-remove-customer-from-group": "Rimuovere il cliente dal gruppo?",
     "country": "Nazione",
     "create-customer-group": "Crea gruppo di clienti",
@@ -376,7 +376,6 @@
     "registered": "Registrato",
     "remove-customers-from-group-success": "Ho rimosso {customerCount, plural, one {1 cuclientestomer} other {{customerCount} clienti}} from \"{ groupName }\"",
     "remove-from-group": "Rimuovi da questo gruppo",
-    "search-by-group-name": "Ricerca termine",
     "search-customers-by-email": "Cerca per indirizzo email",
     "search-customers-by-email-last-name-postal-code": "Cerca per cognome / indirizzo email / CAP",
     "select-customer": "Seleziona cliente",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Aggiunti prodotti all'ordine di test",
     "channel": "Canale",
     "channel-token": "Token del canale",
-    "confirm-delete-payment-method": "Eliminare il metodo di pagamento?",
-    "confirm-delete-role": "Cancellare il ruolo?",
-    "confirm-delete-tax-category": "Cancellare la categoria di tasse?",
-    "confirm-delete-tax-rate": "Cancellare tasso fiscale?",
     "create-new-channel": "Crea nuovo canale",
     "create-new-country": "Crea nuova nazione",
     "create-new-payment-method": "Crea nuovo metodo di pagamento",
@@ -671,7 +666,6 @@
     "eligible": "Compatibile",
     "email-address": "Indirizzo email",
     "emailAddress": "",
-    "filter-by-member-name": "Filtra per nazione",
     "first-name": "Nome",
     "fulfillment-handler": "Gestore spedizione",
     "global-out-of-stock-threshold": "Soglia globale di indisponibilità",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Podgląd cen kanału",
     "collection-contents": "Zawartość kolekcji",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "",
     "confirm-delete-assets": "",
-    "confirm-delete-channel": "Usunąć kanał?",
     "confirm-delete-collection": "Usunąć kolekcje?",
     "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-value": "Usunąć wartość faseta?",
     "confirm-delete-product": "Usunąć produkt?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Usunąć wariant produktu?",
-    "confirm-delete-promotion": "Usunąć promocje?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Usunąć metode wysyłki?",
-    "confirm-delete-zone": "",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Rozwiń wszystkie kolekcje",
     "facet-value-not-available": "",
     "facet-values": "Wartości faseta",
     "filter-by-name": "Filtruj po nazwie",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Zarządzaj wariantami",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Przesuń w dół",
     "move-to": "Przesuń do",
     "move-up": "Przesuń w górę",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Błąd usuwania produktu z kanału",
@@ -158,6 +153,7 @@
     "remove-option": "Usuń opcje",
     "remove-product-from-channel": "Usuń produkt z kanału",
     "remove-product-variant-from-channel": "",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Anuluj",
     "cancel-navigation": "Anuluj nawigacje",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Hasło",
+    "position": "",
     "price": "Cena",
     "price-with-tax": "Cena z podatkiem",
     "private": "Prywatne",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "",
     "results-count": "{ count } {count, plural, one {wynik} other {wyników}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Wybrano...",
     "select-display-language": "Wybierz język",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "",
@@ -315,6 +315,7 @@
     "updated-at": "Zaaktualizowano dnia",
     "username": "Nazwa użytkownika",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Wyświetl następny miesiąc",
     "view-previous-month": "Wyświetl poprzedni miesiąc",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Adres",
     "city": "Miasto",
     "company": "",
-    "confirm-delete-customer-group": "",
     "confirm-remove-customer-from-group": "",
     "country": "Kraj",
     "create-customer-group": "",
@@ -376,7 +376,6 @@
     "registered": "Zarejestrowany",
     "remove-customers-from-group-success": "",
     "remove-from-group": "",
-    "search-by-group-name": "Szukaj frazy",
     "search-customers-by-email": "Szukaj przez email",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Dodaj produkty do testowanego zamówienia",
     "channel": "Kanał",
     "channel-token": "Token kanału",
-    "confirm-delete-payment-method": "",
-    "confirm-delete-role": "Usunąć role?",
-    "confirm-delete-tax-category": "Usunąć kategorię podatkową?",
-    "confirm-delete-tax-rate": "Usunąć stawke podatkową?",
     "create-new-channel": "Utwórz nowy kanał",
     "create-new-country": "Utwórz nowy kraj",
     "create-new-payment-method": "",
@@ -671,7 +666,6 @@
     "eligible": "Wybieralny",
     "email-address": "Email",
     "emailAddress": "",
-    "filter-by-member-name": "",
     "first-name": "Imię",
     "fulfillment-handler": "",
     "global-out-of-stock-threshold": "",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Visualizar preço do canal",
     "collection-contents": "Conteúdo da categoria",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Excluir administrador?",
     "confirm-delete-assets": "Excluir {count} {count, plural, one {asset} other {assets}}?",
-    "confirm-delete-channel": "Exluir canal?",
     "confirm-delete-collection": "Excluir categorias?",
     "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-value": "Excluir valor da etiqueta?",
     "confirm-delete-product": "Excluir produto?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Excluir variação de produto?",
-    "confirm-delete-promotion": "Excluir promoção?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Excluir método de envio?",
-    "confirm-delete-zone": "Excluir zona?",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Expandir todas as categorias",
     "facet-value-not-available": "",
     "facet-values": "Valor da Etiqueta",
     "filter-by-name": "Filtrar por nome",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Gerência das variações",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Mover para baixo",
     "move-to": "Mover para",
     "move-up": "Mover para cima",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Não foi possível remover o produto do canal",
@@ -158,6 +153,7 @@
     "remove-option": "Excluir opção",
     "remove-product-from-channel": "Excluir produto do canal",
     "remove-product-variant-from-channel": "",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Cancelar",
     "cancel-navigation": "Cancelar navegação",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Senha",
+    "position": "",
     "price": "Preço",
     "price-with-tax": "Preço com impostos",
     "private": "Privado",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "",
     "results-count": "{ count } {count, plural, one {result} other {results}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Selecione...",
     "select-display-language": "Selecionar idioma de exibição",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "",
@@ -315,6 +315,7 @@
     "updated-at": "Atualizado em",
     "username": "Nome do usuário",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Visualizar próximo mês",
     "view-previous-month": "Visualizar mês anterior",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Endereços",
     "city": "Cidade",
     "company": "",
-    "confirm-delete-customer-group": "Excluir grupo de cliente?",
     "confirm-remove-customer-from-group": "Excluir cliente do grupo?",
     "country": "País",
     "create-customer-group": "Criar grupo de cliente",
@@ -376,7 +376,6 @@
     "registered": "Registrado",
     "remove-customers-from-group-success": "Excluído {customerCount, plural, one {1 customer} other {{customerCount} customers}} from \"{ groupName }\"",
     "remove-from-group": "Excluir deste grupo",
-    "search-by-group-name": "Pesquisar termo",
     "search-customers-by-email": "Busca por email",
     "search-customers-by-email-last-name-postal-code": "Busca por email / sobrenome / cep",
     "select-customer": "",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Adicionar produdos para o pedido de teste",
     "channel": "Canal",
     "channel-token": "Token do canal",
-    "confirm-delete-payment-method": "",
-    "confirm-delete-role": "Exluir regra?",
-    "confirm-delete-tax-category": "Excluir categoria de imposto?",
-    "confirm-delete-tax-rate": "Excluir taxa de imposto?",
     "create-new-channel": "Criar novo canal",
     "create-new-country": "Criar novo país",
     "create-new-payment-method": "",
@@ -671,7 +666,6 @@
     "eligible": "Elegível",
     "email-address": "Email",
     "emailAddress": "",
-    "filter-by-member-name": "Filtrar por país",
     "first-name": "Nome",
     "fulfillment-handler": "Manipulador de preenchimento",
     "global-out-of-stock-threshold": "Limite global de falta de estoque",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/pt_PT.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Visualizar preço do canal",
     "collection-contents": "Conteúdo da categoria",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Eliminar administrador?",
     "confirm-delete-assets": "Eliminar {count} {count, plural, one {imagem} other {imagens}}?",
-    "confirm-delete-channel": "Exluir canal?",
     "confirm-delete-collection": "Eliminar categorias?",
     "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-value": "Eliminar valor da etiqueta?",
     "confirm-delete-product": "Eliminar produto?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Eliminar variante do produto?",
-    "confirm-delete-promotion": "Eliminar promoção?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Eliminar método de envio?",
-    "confirm-delete-zone": "Eliminar região?",
     "confirm-deletion-of-unused-variants-body": "As variantes listadas abaixo estão obsoletas e serão eliminadas devido à adição de novas opções.",
     "confirm-deletion-of-unused-variants-title": "Eliminar as variantes obsoletas?",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Certifique-se de que todos os SKUs sejam únicos",
     "edit-facet-values": "",
     "edit-options": "Editar opções",
-    "expand-all-collections": "Expandir todas as categorias",
     "facet-value-not-available": "",
     "facet-values": "Valor da Etiqueta",
     "filter-by-name": "Filtrar por nome",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Gerir variações",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Mover para baixo",
     "move-to": "Mover para",
     "move-up": "Mover para cima",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Não foi possível remover o produto do canal",
@@ -158,6 +153,7 @@
     "remove-option": "Eliminar opção",
     "remove-product-from-channel": "Eliminar produto do canal",
     "remove-product-variant-from-channel": "Remover variante do canal?",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "Executar {count, plural, one {1 actualização pendente} other {{count} actualizações pendentes}}",
     "running-search-index-updates": "A executar {count, plural, one {1 actualização} other {{count} actualizações}}",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "Navegador padrão",
     "cancel": "Cancelar",
     "cancel-navigation": "Continuar a editar",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Palavra passe",
+    "position": "",
     "price": "Preço",
     "price-with-tax": "Preço com impostos",
     "private": "Privado",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Remover item da lista",
     "results-count": "{ count } {count, plural, one {resultado} other {resultados}}",
     "sample-formatting": "Formatação de amostra",
+    "search-by-name": "",
     "select": "Seleccione...",
     "select-display-language": "Seleccionar idioma",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "Definir idioma",
     "short-date": "Data abreviada",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Tags",
@@ -315,6 +315,7 @@
     "updated-at": "Actualizado em",
     "username": "Nome do utilizador",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Visualizar próximo mês",
     "view-previous-month": "Visualizar mês anterior",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Moradas",
     "city": "Cidade",
     "company": "",
-    "confirm-delete-customer-group": "Eliminar grupo de cliente?",
     "confirm-remove-customer-from-group": "Eliminar cliente do grupo?",
     "country": "País",
     "create-customer-group": "Criar grupo de cliente",
@@ -376,7 +376,6 @@
     "registered": "Registado",
     "remove-customers-from-group-success": "{customerCount, plural, one {1 cliente eliminado} other {{customerCount} clientes eliminados}} do grupo \"{ groupName }\"",
     "remove-from-group": "Eliminar deste grupo",
-    "search-by-group-name": "Pesquisar termo",
     "search-customers-by-email": "Pesquisar por email",
     "search-customers-by-email-last-name-postal-code": "Pesquisar pelo apelido / email / código postal",
     "select-customer": "Seleccione o cliente",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Adicionar produdos para a encomenda de teste",
     "channel": "Canal",
     "channel-token": "Token do canal",
-    "confirm-delete-payment-method": "Eliminar método de pagamento?",
-    "confirm-delete-role": "Eliminar regra?",
-    "confirm-delete-tax-category": "Eliminar categoria de imposto?",
-    "confirm-delete-tax-rate": "Eliminar taxa de imposto?",
     "create-new-channel": "Criar novo canal",
     "create-new-country": "Criar novo país",
     "create-new-payment-method": "Criar novo método de pagamento",
@@ -671,7 +666,6 @@
     "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",
     "global-out-of-stock-threshold": "Limite globalpara fora de estoque",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/ru.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Предварительный просмотр цен канала",
     "collection-contents": "Содержание коллекции",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Удалить администратора?",
     "confirm-delete-assets": "Удалить {count} {count, plural, one {медиа-объект} other {медиа-объектов}}?",
-    "confirm-delete-channel": "Удалить канал?",
     "confirm-delete-collection": "Удалить коллекцию?",
     "confirm-delete-collection-and-children-body": "Удаление этой коллекции также приведет к удалению всех дочерних коллекций.",
-    "confirm-delete-country": "Удалить страну?",
-    "confirm-delete-customer": "Удалить клиента?",
     "confirm-delete-facet-value": "Удалить значение тега?",
     "confirm-delete-product": "Удалить товар?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Удалить вариант товара?",
-    "confirm-delete-promotion": "Удалить промо-акцию?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Удалить способ доставки?",
-    "confirm-delete-zone": "Удалить зону?",
     "confirm-deletion-of-unused-variants-body": "Следующие варианты товаров устарели из за добавления новых опций. Они будут удалены во время создания новых вариантов товара.",
     "confirm-deletion-of-unused-variants-title": "Удалить устаревшие варианты товара?",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Убедитесь, что все артикулы (SKU) уникальны",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Развернуть все коллекции",
     "facet-value-not-available": "",
     "facet-values": "Значения тега",
     "filter-by-name": "Фильтр по имени",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Управление вариантами",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Двигать вниз",
     "move-to": "Двигать к",
     "move-up": "Двигать вверх",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Не удалось удалить товар из канала",
@@ -158,6 +153,7 @@
     "remove-option": "Удалить опции",
     "remove-product-from-channel": "Удалить товар из канала",
     "remove-product-variant-from-channel": "Удалить вариант товара из канала",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Отмена",
     "cancel-navigation": "Отменить навигацию",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Пароль",
+    "position": "",
     "price": "Цена",
     "price-with-tax": "Цена с налогом",
     "private": "Служебная",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Удалить позицию из списка",
     "results-count": "{ count } {count, plural, one {результат} other {результатов}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Выбрать...",
     "select-display-language": "Выберите язык отображения",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Теги",
@@ -315,6 +315,7 @@
     "updated-at": "Обновлено в",
     "username": "Имя пользователя",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Посмотреть следующий месяц",
     "view-previous-month": "Посмотреть предыдущий месяц",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Адреса",
     "city": "Город",
     "company": "",
-    "confirm-delete-customer-group": "Удалить группу клиентов?",
     "confirm-remove-customer-from-group": "Удалить клиента из группы?",
     "country": "Страна",
     "create-customer-group": "Создать группу клиентов",
@@ -376,7 +376,6 @@
     "registered": "Зарегистрировано",
     "remove-customers-from-group-success": "Удален {customerCount, plural, one {1 клиент} other {{customerCount} клиентов}} из \"{ groupName }\"",
     "remove-from-group": "Удалить из этой группы",
-    "search-by-group-name": "Искать по фразе",
     "search-customers-by-email": "Поиск по адресу электронной почты",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Выберите клиента",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Добавить товары в тестовый заказ",
     "channel": "Канал",
     "channel-token": "Токен канала",
-    "confirm-delete-payment-method": "Удалить способ оплаты?",
-    "confirm-delete-role": "Удалить роль?",
-    "confirm-delete-tax-category": "Удалить налоговую категорию?",
-    "confirm-delete-tax-rate": "Удалить налоговую ставку?",
     "create-new-channel": "Создать новый канал",
     "create-new-country": "Создать новую страну",
     "create-new-payment-method": "Создать новый способ оплаты",
@@ -671,7 +666,6 @@
     "eligible": "Имеющий право",
     "email-address": "Адрес электронной почты",
     "emailAddress": "",
-    "filter-by-member-name": "Фильтровать по стране",
     "first-name": "Имя",
     "fulfillment-handler": "Обработчик выполнения",
     "global-out-of-stock-threshold": "Глобальный порог отсутствия на складе",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/uk.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "Попередній перегляд цін каналу",
     "collection-contents": "Зміст колекції",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "Видалити адміністратора?",
     "confirm-delete-assets": "Видалити {count} {count, plural, one {медіа-об'єкт} other {медіа-об'єктів}}?",
-    "confirm-delete-channel": "Видалити канал?",
     "confirm-delete-collection": "Видалити колекцію?",
     "confirm-delete-collection-and-children-body": "Видалення цієї колекції також призведе до видалення всіх дочірніх колекцій.",
-    "confirm-delete-country": "Видалити країну?",
-    "confirm-delete-customer": "Видалити клієнта?",
     "confirm-delete-facet-value": "Видалити значення тегу?",
     "confirm-delete-product": "Видалити товар?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "Видалити варіант товару?",
-    "confirm-delete-promotion": "Видалити промо-акцію?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "Видалити спосіб доставки?",
-    "confirm-delete-zone": "Видалити зону?",
     "confirm-deletion-of-unused-variants-body": "Наступні варіанти товару застаріли через додавання нових опцій. Вони будуть видалені під час створення нових варіантів товару.",
     "confirm-deletion-of-unused-variants-title": "Видалити застарілі варіанти товару?",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "Переконайтесь, що всі артикули (SKU) унікальні",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "Розгорнути всі колекції",
     "facet-value-not-available": "",
     "facet-values": "Значення тегу",
     "filter-by-name": "Фільтр по імені",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "Управління варіантами",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "Рухати вниз",
     "move-to": "Рухати до",
     "move-up": "Рухати вгору",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "Не вдалося видалити товар з каналу",
@@ -158,6 +153,7 @@
     "remove-option": "Видалити опції",
     "remove-product-from-channel": "Видалити товар з каналу",
     "remove-product-variant-from-channel": "Видалити варіант товару з каналу",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "Скасування",
     "cancel-navigation": "Скасувати навігацію",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "Пароль",
+    "position": "",
     "price": "Ціна",
     "price-with-tax": "Ціна з податком",
     "private": "Службова",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "Видалити позицію зі списку",
     "results-count": "{ count } {count, plural, one {результат} other {результатів}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "Вибрати...",
     "select-display-language": "Виберіть мову відображення",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "Теги",
@@ -315,6 +315,7 @@
     "updated-at": "Оновлено в",
     "username": "Ім'я користувача",
     "value": "",
+    "view-contents": "",
     "view-next-month": "Переглянути наступний місяць",
     "view-previous-month": "Переглянути попередній місяць",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "Адреси",
     "city": "Місто",
     "company": "",
-    "confirm-delete-customer-group": "Видалити групу клієнтів?",
     "confirm-remove-customer-from-group": "Видалити клієнта з групи?",
     "country": "Країна",
     "create-customer-group": "Створити групу клієнтів",
@@ -376,7 +376,6 @@
     "registered": "Зареєстровано",
     "remove-customers-from-group-success": "Видалено {customerCount, plural, one {1 клієнт} other {{customerCount} клієнтів}} из \"{ groupName }\"",
     "remove-from-group": "Вилучити з цієї групи",
-    "search-by-group-name": "Шукати по фразі",
     "search-customers-by-email": "Пошук за адресою електронної пошти",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "Виберіть клієнта",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "Додати товари до тестового замовлення",
     "channel": "Канал",
     "channel-token": "Токен каналу",
-    "confirm-delete-payment-method": "Видалити спосіб оплати?",
-    "confirm-delete-role": "Видалити роль?",
-    "confirm-delete-tax-category": "Видалити податкову категорію?",
-    "confirm-delete-tax-rate": "Видалити податкову ставку?",
     "create-new-channel": "Створити новий канал",
     "create-new-country": "Створити нову країну",
     "create-new-payment-method": "Створити новий спосіб оплати",
@@ -671,7 +666,6 @@
     "eligible": "Який має право",
     "email-address": "Адреса електронної пошти",
     "emailAddress": "",
-    "filter-by-member-name": "Фільтрувати по країні",
     "first-name": "Ім'я",
     "fulfillment-handler": "Обробник виконання",
     "global-out-of-stock-threshold": "Глобальний поріг відсутності на складі",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "渠道价格预览",
     "collection-contents": "系列产品",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "确认删除管理员吗?",
     "confirm-delete-assets": "确认删除{count}个资源吗?",
-    "confirm-delete-channel": "确认删除销售渠道?",
     "confirm-delete-collection": "确认删除商品系列吗?",
     "confirm-delete-collection-and-children-body": "删除这个系列会删除它所包含的子系列,确认删除码?",
-    "confirm-delete-country": "确认删除国家?",
-    "confirm-delete-customer": "确认删除客户吗?",
     "confirm-delete-facet-value": "确认删除特征值?",
     "confirm-delete-product": "确认删除商品?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "确认删除商品规格?",
-    "confirm-delete-promotion": "确认删除优惠券?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "确认删除邮寄方式?",
-    "confirm-delete-zone": "确认删除分区么?",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "展开所有系列",
     "facet-value-not-available": "",
     "facet-values": "特征值列表",
     "filter-by-name": "按名字过滤",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "商品规格管理",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "向下移",
     "move-to": "移至",
     "move-up": "向上移",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "从渠道中移除商品失败",
@@ -158,6 +153,7 @@
     "remove-option": "移除选项",
     "remove-product-from-channel": "从销售渠道移除商品",
     "remove-product-variant-from-channel": "从销售渠道移除商品变体",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "取消",
     "cancel-navigation": "取消",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "密码",
+    "position": "",
     "price": "价格",
     "price-with-tax": "价格(含税)",
     "private": "隐藏",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "从列表中移除",
     "results-count": "{count, plural, =0{无} other {{count}个过滤结果}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "选择...",
     "select-display-language": "选择显示语言",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "标签",
@@ -315,6 +315,7 @@
     "updated-at": "修改时间",
     "username": "用户名",
     "value": "",
+    "view-contents": "",
     "view-next-month": "查看下个月",
     "view-previous-month": "查看下个月",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "地址",
     "city": "市",
     "company": "",
-    "confirm-delete-customer-group": "确认删除客户分组?",
     "confirm-remove-customer-from-group": "确认从分组移除客户?",
     "country": "国家",
     "create-customer-group": "添加分组",
@@ -376,7 +376,6 @@
     "registered": "已注册",
     "remove-customers-from-group-success": "成功从分组\"{ groupName }\"中移除{customerCount}个客户",
     "remove-from-group": "从分组中移除",
-    "search-by-group-name": "输入搜索条目",
     "search-customers-by-email": "输入要搜索的客户邮件地址",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "选择客户",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "添加产品到测试订单",
     "channel": "销售渠道",
     "channel-token": "渠道唯一码",
-    "confirm-delete-payment-method": "确认删除付款方式?",
-    "confirm-delete-role": "确认删除角色?",
-    "confirm-delete-tax-category": "确认删除税表分类?",
-    "confirm-delete-tax-rate": "去人删除税率?",
     "create-new-channel": "添加销售渠道",
     "create-new-country": "添加国家",
     "create-new-payment-method": "",
@@ -671,7 +666,6 @@
     "eligible": "符合条件",
     "email-address": "电子邮件",
     "emailAddress": "",
-    "filter-by-member-name": "",
     "first-name": "名",
     "fulfillment-handler": "",
     "global-out-of-stock-threshold": "默认售空限制",

+ 12 - 18
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -71,26 +71,19 @@
     "channel-price-preview": "渠道價格覽",
     "collection-contents": "系列產品",
     "collection-slug": "",
+    "confirm-bulk-delete": "",
     "confirm-bulk-delete-collections": "",
-    "confirm-bulk-delete-facets": "",
     "confirm-bulk-delete-products": "",
     "confirm-cancel": "",
     "confirm-delete-administrator": "",
     "confirm-delete-assets": "",
-    "confirm-delete-channel": "確認移除渠道?",
     "confirm-delete-collection": "確認移除商品系列吗?",
     "confirm-delete-collection-and-children-body": "移除這個系列會移除它所包含的子系列,確認移除嗎?",
-    "confirm-delete-country": "確認移除此國家?",
-    "confirm-delete-customer": "",
     "confirm-delete-facet-value": "確認移除特徵值?",
     "confirm-delete-product": "確認移除商品?",
     "confirm-delete-product-option": "",
     "confirm-delete-product-option-group": "",
     "confirm-delete-product-variant": "確認移除商品規格?",
-    "confirm-delete-promotion": "確認移除優惠券?",
-    "confirm-delete-seller": "",
-    "confirm-delete-shipping-method": "確認移除此郵寄方式?",
-    "confirm-delete-zone": "",
     "confirm-deletion-of-unused-variants-body": "",
     "confirm-deletion-of-unused-variants-title": "",
     "create-draft-order": "",
@@ -106,7 +99,6 @@
     "duplicate-sku-warning": "",
     "edit-facet-values": "",
     "edit-options": "",
-    "expand-all-collections": "展開所有系列",
     "facet-value-not-available": "",
     "facet-values": "特徵值列表",
     "filter-by-name": "按名字篩選",
@@ -117,6 +109,9 @@
     "inherit-filters-from-parent": "",
     "live-preview-contents": "",
     "manage-variants": "商品規格管理",
+    "move-collection-to": "",
+    "move-collections": "",
+    "move-collections-success": "",
     "move-down": "下移",
     "move-to": "移至",
     "move-up": "上移",
@@ -125,9 +120,9 @@
     "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-delete-error-with-count": "",
+    "notify-delete-success-with-count": "",
     "notify-remove-collections-from-channel-success": "",
     "notify-remove-facets-from-channel-success": "",
     "notify-remove-product-from-channel-error": "從渠道中移除商品失敗",
@@ -158,6 +153,7 @@
     "remove-option": "移除選項",
     "remove-product-from-channel": "從渠道移除商品",
     "remove-product-variant-from-channel": "",
+    "reorder-collection": "",
     "root-collection": "",
     "run-pending-search-index-updates": "",
     "running-search-index-updates": "",
@@ -203,6 +199,7 @@
     "boolean-false": "",
     "boolean-or": "",
     "boolean-true": "",
+    "breadcrumb": "",
     "browser-default": "",
     "cancel": "取消",
     "cancel-navigation": "取消",
@@ -284,6 +281,7 @@
     "operator-notContains": "",
     "operator-regex": "",
     "password": "密碼",
+    "position": "",
     "price": "價格",
     "price-with-tax": "價格(連税)",
     "private": "隱藏",
@@ -293,6 +291,7 @@
     "remove-item-from-list": "",
     "results-count": "{count, plural, =0{無} other {{count}個篩選結果}}",
     "sample-formatting": "",
+    "search-by-name": "",
     "select": "選擇...",
     "select-display-language": "選擇顯示語言",
     "select-items-with-count": "",
@@ -304,6 +303,7 @@
     "seller": "",
     "set-language": "",
     "short-date": "",
+    "slug": "",
     "start-date": "",
     "status": "",
     "tags": "",
@@ -315,6 +315,7 @@
     "updated-at": "修改時間",
     "username": "用户名",
     "value": "",
+    "view-contents": "",
     "view-next-month": "查看下個月",
     "view-previous-month": "查看上個月",
     "visibility": "",
@@ -330,7 +331,6 @@
     "addresses": "地址",
     "city": "市",
     "company": "",
-    "confirm-delete-customer-group": "",
     "confirm-remove-customer-from-group": "",
     "country": "國家",
     "create-customer-group": "",
@@ -376,7 +376,6 @@
     "registered": "已注册",
     "remove-customers-from-group-success": "",
     "remove-from-group": "",
-    "search-by-group-name": "輸入搜索條目",
     "search-customers-by-email": "輸入要搜索的客户電郵地址",
     "search-customers-by-email-last-name-postal-code": "",
     "select-customer": "",
@@ -650,10 +649,6 @@
     "add-products-to-test-order": "新增產品到測試訂單",
     "channel": "渠道",
     "channel-token": "渠道唯一碼",
-    "confirm-delete-payment-method": "",
-    "confirm-delete-role": "確認移除角色?",
-    "confirm-delete-tax-category": "確認移除税表分類?",
-    "confirm-delete-tax-rate": "確認移除税率?",
     "create-new-channel": "新增渠道",
     "create-new-country": "新增國家",
     "create-new-payment-method": "",
@@ -671,7 +666,6 @@
     "eligible": "符合條件",
     "email-address": "電子郵件",
     "emailAddress": "",
-    "filter-by-member-name": "",
     "first-name": "名",
     "fulfillment-handler": "",
     "global-out-of-stock-threshold": "",