Quellcode durchsuchen

chore(admin-ui): Refactor data table search

Michael Bromley vor 2 Jahren
Ursprung
Commit
06cfd37a3e

+ 134 - 138
packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.html

@@ -1,71 +1,5 @@
-<vdr-action-bar>
-    <vdr-ab-left [grow]="true">
-        <div class="search-form">
-            <vdr-product-search-input
-                #productSearchInputComponent
-                [facetValueResults]="facetValues$ | async"
-                (searchTermChange)="setSearchTerm($event)"
-                (facetValueChange)="setFacetValueIds($event)"
-            ></vdr-product-search-input>
-            <vdr-dropdown class="search-settings-menu mr3">
-                <button
-                    type="button"
-                    class="icon-button search-index-button"
-                    [title]="
-                        (pendingSearchIndexUpdates
-                            ? 'catalog.pending-search-index-updates'
-                            : 'catalog.search-index-controls'
-                        ) | translate
-                    "
-                    vdrDropdownTrigger
-                >
-                    <clr-icon shape="cog"></clr-icon>
-                    <vdr-status-badge *ngIf="pendingSearchIndexUpdates" type="warning"></vdr-status-badge>
-                </button>
-                <vdr-dropdown-menu vdrPosition="bottom-right">
-                    <h4 class="dropdown-header">{{ 'catalog.search-index-controls' | translate }}</h4>
-                    <ng-container *ngIf="pendingSearchIndexUpdates">
-                        <button
-                            type="button"
-                            class="run-updates-button"
-                            vdrDropdownItem
-                            (click)="runPendingSearchIndexUpdates()"
-                            [disabled]="!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)"
-                        >
-                            <vdr-status-badge type="warning"></vdr-status-badge>
-                            {{
-                                'catalog.run-pending-search-index-updates'
-                                    | translate: { count: pendingSearchIndexUpdates }
-                            }}
-                        </button>
-                        <div class="dropdown-divider"></div>
-                    </ng-container>
-                    <button
-                        type="button"
-                        vdrDropdownItem
-                        (click)="rebuildSearchIndex()"
-                        [disabled]="!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)"
-                    >
-                        {{ 'catalog.rebuild-search-index' | translate }}
-                    </button>
-                </vdr-dropdown-menu>
-            </vdr-dropdown>
-        </div>
-        <div class="flex wrap">
-            <clr-toggle-wrapper class="mt-2">
-                <input type="checkbox" clrToggle [(ngModel)]="groupByProduct" (ngModelChange)="refresh()" />
-                <label>
-                    {{ 'catalog.group-by-product' | translate }}
-                </label>
-            </clr-toggle-wrapper>
-            <vdr-language-selector
-                [availableLanguageCodes]="availableLanguages$ | async"
-                [currentLanguageCode]="contentLanguage$ | async"
-                (languageCodeChange)="setLanguage($event)"
-            ></vdr-language-selector>
-        </div>
-    </vdr-ab-left>
-    <vdr-ab-right>
+<vdr-page-header>
+    <vdr-page-title>
         <vdr-action-bar-items locationId="product-list"></vdr-action-bar-items>
         <a
             class="btn btn-primary"
@@ -75,78 +9,140 @@
             <clr-icon shape="plus"></clr-icon>
             {{ 'catalog.create-new-product' | translate }}
         </a>
-    </vdr-ab-right>
-</vdr-action-bar>
-
-<vdr-data-table
-    [items]="items$ | async"
-    [itemsPerPage]="itemsPerPage$ | async"
-    [totalItems]="totalItems$ | async"
-    [currentPage]="currentPage$ | async"
-    (pageChange)="setPageNumber($event)"
-    (itemsPerPageChange)="setItemsPerPage($event)"
-    [selectionManager]="selectionManager"
->
-    <vdr-bulk-action-menu
-        locationId="product-list"
-        [hostComponent]="this"
+    </vdr-page-title>
+</vdr-page-header>
+<vdr-page-body>
+    <div class="flex wrap ml-4">
+        <clr-toggle-wrapper class="mt-2">
+            <input type="checkbox" clrToggle [(ngModel)]="groupByProduct" (ngModelChange)="refresh()" />
+            <label>
+                {{ 'catalog.group-by-product' | translate }}
+            </label>
+        </clr-toggle-wrapper>
+        <vdr-language-selector
+            [availableLanguageCodes]="availableLanguages$ | async"
+            [currentLanguageCode]="contentLanguage$ | async"
+            (languageCodeChange)="setLanguage($event)"
+        ></vdr-language-selector>
+    </div>
+    <vdr-data-table-2
+        class="mt-2"
+        id="product-list"
+        [items]="items$ | async"
+        [itemsPerPage]="itemsPerPage$ | async"
+        [totalItems]="totalItems$ | async"
+        [currentPage]="currentPage$ | async"
+        [filters]="filters"
         [selectionManager]="selectionManager"
-    ></vdr-bulk-action-menu>
-    <vdr-dt-column> </vdr-dt-column>
-    <vdr-dt-column></vdr-dt-column>
-    <vdr-dt-column></vdr-dt-column>
-    <vdr-dt-column></vdr-dt-column>
-    <ng-template let-result="item">
-        <td class="left align-middle image-col" [class.disabled]="!result.enabled">
-            <div class="image-placeholder">
-                <img
-                    *ngIf="
-                        groupByProduct
-                            ? result.productAsset
-                            : result.productVariantAsset || result.productAsset as asset;
-                        else imagePlaceholder
-                    "
-                    [src]="asset | assetPreview: 'tiny'"
-                />
-                <ng-template #imagePlaceholder>
-                    <div class="placeholder">
-                        <clr-icon shape="image" size="48"></clr-icon>
-                    </div>
-                </ng-template>
-            </div>
-        </td>
-        <td class="left align-middle" [class.disabled]="!result.enabled">
-            <div>{{ groupByProduct ? result.productName : result.productVariantName }}</div>
-            <div *ngIf="!groupByProduct" class="sku">{{ result.sku }}</div>
-        </td>
-        <td class="align-middle" [class.disabled]="!result.enabled">
-            <vdr-chip *ngIf="!result.enabled">{{ 'common.disabled' | translate }}</vdr-chip>
-        </td>
-        <td class="right align-middle" [class.disabled]="!result.enabled">
-            <vdr-table-row-action
-                class="edit-button"
-                iconShape="edit"
-                [label]="'common.edit' | translate"
-                [linkTo]="['./', result.productId]"
-            ></vdr-table-row-action>
-            <vdr-dropdown>
-                <button type="button" class="btn btn-link btn-sm" vdrDropdownTrigger>
-                    {{ 'common.actions' | translate }}
-                    <clr-icon shape="caret down"></clr-icon>
-                </button>
-                <vdr-dropdown-menu vdrPosition="bottom-right">
+        (pageChange)="setPageNumber($event)"
+        (itemsPerPageChange)="setItemsPerPage($event)"
+    >
+        <vdr-bulk-action-menu
+            locationId="product-list"
+            [hostComponent]="this"
+            [selectionManager]="selectionManager"
+        ></vdr-bulk-action-menu>
+        <ng-template #vdrDt2CustomSearch>
+            <div class="search-form">
+                <vdr-product-search-input
+                    #productSearchInputComponent
+                    [facetValueResults]="facetValues$ | async"
+                    (searchTermChange)="setSearchTerm($event)"
+                    (facetValueChange)="setFacetValueIds($event)"
+                ></vdr-product-search-input>
+                <vdr-dropdown class="search-settings-menu mr3">
                     <button
                         type="button"
-                        class="delete-button"
-                        (click)="deleteProduct(result.productId)"
-                        [disabled]="!(['DeleteCatalog', 'DeleteProduct'] | hasPermission)"
-                        vdrDropdownItem
+                        class="icon-button search-index-button"
+                        [title]="
+                            (pendingSearchIndexUpdates
+                                ? 'catalog.pending-search-index-updates'
+                                : 'catalog.search-index-controls'
+                            ) | translate
+                        "
+                        vdrDropdownTrigger
                     >
-                        <clr-icon shape="trash" class="is-danger"></clr-icon>
-                        {{ 'common.delete' | translate }}
+                        <clr-icon shape="cog"></clr-icon>
+                        <vdr-status-badge *ngIf="pendingSearchIndexUpdates" type="warning"></vdr-status-badge>
                     </button>
-                </vdr-dropdown-menu>
-            </vdr-dropdown>
-        </td>
-    </ng-template>
-</vdr-data-table>
+                    <vdr-dropdown-menu vdrPosition="bottom-right">
+                        <h4 class="dropdown-header">{{ 'catalog.search-index-controls' | translate }}</h4>
+                        <ng-container *ngIf="pendingSearchIndexUpdates">
+                            <button
+                                type="button"
+                                class="run-updates-button"
+                                vdrDropdownItem
+                                (click)="runPendingSearchIndexUpdates()"
+                                [disabled]="!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)"
+                            >
+                                <vdr-status-badge type="warning"></vdr-status-badge>
+                                {{
+                                    'catalog.run-pending-search-index-updates'
+                                        | translate : { count: pendingSearchIndexUpdates }
+                                }}
+                            </button>
+                            <div class="dropdown-divider"></div>
+                        </ng-container>
+                        <button
+                            type="button"
+                            vdrDropdownItem
+                            (click)="rebuildSearchIndex()"
+                            [disabled]="!(['UpdateCatalog', 'UpdateProduct'] | hasPermission)"
+                        >
+                            {{ 'catalog.rebuild-search-index' | translate }}
+                        </button>
+                    </vdr-dropdown-menu>
+                </vdr-dropdown>
+            </div>
+        </ng-template>
+        <vdr-dt2-column [heading]="'common.image' | translate">
+            <ng-template let-result="item">
+                <div class="image-placeholder">
+                    <img
+                        *ngIf="
+                            groupByProduct
+                                ? result.productAsset
+                                : result.productVariantAsset || result.productAsset as asset;
+                            else imagePlaceholder
+                        "
+                        [src]="asset | assetPreview : 'tiny'"
+                    />
+                    <ng-template #imagePlaceholder>
+                        <div class="placeholder">
+                            <clr-icon shape="image" size="48"></clr-icon>
+                        </div>
+                    </ng-template>
+                </div>
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'catalog.name' | translate" [optional]="false">
+            <ng-template let-result="item">
+                <a class="button-ghost" [routerLink]="['./', result.productId]"
+                    ><span>{{ groupByProduct ? result.productName : result.productVariantName }}</span
+                    ><clr-icon shape="arrow right"
+                /></a>
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'catalog.sku' | translate" [optional]="false">
+            <ng-template let-result="item">
+                {{ result.sku }}
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'common.enabled' | translate">
+            <ng-template let-result="item">
+                <vdr-chip *ngIf="!result.enabled">{{ 'common.disabled' | translate }}</vdr-chip>
+            </ng-template>
+        </vdr-dt2-column>
+        <vdr-dt2-column [heading]="'catalog.price' | translate">
+            <ng-template let-result="item">
+                <span *ngIf="result.priceWithTax.min"
+                    >{{ result.priceWithTax.min | localeCurrency : result.currencyCode }} -
+                    {{ result.priceWithTax.max | localeCurrency : result.currencyCode }}</span
+                >
+                <span *ngIf="result.priceWithTax.value">{{
+                    result.priceWithTax.value | localeCurrency : result.currencyCode
+                }}</span>
+            </ng-template>
+        </vdr-dt2-column>
+    </vdr-data-table-2>
+</vdr-page-body>

+ 17 - 5
packages/admin-ui/src/lib/catalog/src/components/product-list/product-list.component.ts

@@ -11,6 +11,7 @@ import {
     LogicalOperator,
     ModalService,
     NotificationService,
+    OrderFilterParameter,
     ProductSearchInputComponent,
     SearchInput,
     SearchProductsQuery,
@@ -20,6 +21,7 @@ import {
 } from '@vendure/admin-ui/core';
 import { EMPTY, Observable } from 'rxjs';
 import { delay, map, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
+import { DataTableFilterService } from '../../../../core/src/providers/data-table-filter/data-table-filter.service';
 
 export type SearchItem = ItemOf<SearchProductsQuery, 'search'>;
 
@@ -29,11 +31,7 @@ export type SearchItem = ItemOf<SearchProductsQuery, 'search'>;
     styleUrls: ['./product-list.component.scss'],
 })
 export class ProductListComponent
-    extends BaseListComponent<
-        SearchProductsQuery,
-        SearchItem,
-        SearchProductsQueryVariables
-    >
+    extends BaseListComponent<SearchProductsQuery, SearchItem, SearchProductsQueryVariables>
     implements OnInit, AfterViewInit
 {
     searchTerm = '';
@@ -45,6 +43,17 @@ export class ProductListComponent
     contentLanguage$: Observable<LanguageCode>;
     pendingSearchIndexUpdates = 0;
     selectionManager: SelectionManager<SearchItem>;
+    readonly filters = this.dataTableFilterService
+        .createConfig<SearchInput>()
+        .addFilter({
+            id: 'collectionSlug',
+            type: { kind: 'text' },
+            label: _('catalog.collection-slug'),
+            toFilterInput: value => ({
+                collectionSlug: value.term,
+            }),
+        })
+        .connectToRoute(this.route);
 
     @ViewChild('productSearchInputComponent', { static: true })
     private productSearchInput: ProductSearchInputComponent;
@@ -55,6 +64,7 @@ export class ProductListComponent
         private notificationService: NotificationService,
         private jobQueueService: JobQueueService,
         private serverConfigService: ServerConfigService,
+        private dataTableFilterService: DataTableFilterService,
         router: Router,
         route: ActivatedRoute,
     ) {
@@ -118,6 +128,8 @@ export class ProductListComponent
             .mapStream(({ uiState }) => uiState.contentLanguage)
             .pipe(tap(() => this.refresh()));
 
+        this.filters.valueChanges.subscribe(() => this.refresh());
+
         this.dataService.product
             .getPendingSearchIndexUpdates()
             .mapSingle(({ pendingSearchIndexUpdates }) => pendingSearchIndexUpdates)

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

@@ -7127,7 +7127,7 @@ export type SearchProductsQueryVariables = Exact<{
 }>;
 
 
-export type SearchProductsQuery = { search: { __typename?: 'SearchResponse', totalItems: number, items: Array<{ __typename?: 'SearchResult', enabled: boolean, productId: string, productName: string, productVariantId: string, productVariantName: string, sku: string, channelIds: Array<string>, productAsset?: { __typename?: 'SearchResultAsset', id: string, preview: string, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null, productVariantAsset?: { __typename?: 'SearchResultAsset', id: string, preview: string, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null }>, facetValues: Array<{ __typename?: 'FacetValueResult', count: number, facetValue: { __typename?: 'FacetValue', id: string, createdAt: any, updatedAt: any, name: string, facet: { __typename?: 'Facet', id: string, createdAt: any, updatedAt: any, name: string } } }> } };
+export type SearchProductsQuery = { search: { __typename?: 'SearchResponse', totalItems: number, items: Array<{ __typename?: 'SearchResult', enabled: boolean, productId: string, productName: string, slug: string, currencyCode: CurrencyCode, productVariantId: string, productVariantName: string, sku: string, channelIds: Array<string>, priceWithTax: { __typename?: 'PriceRange', min: number, max: number } | { __typename?: 'SinglePrice', value: number }, productAsset?: { __typename?: 'SearchResultAsset', id: string, preview: string, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null, productVariantAsset?: { __typename?: 'SearchResultAsset', id: string, preview: string, focalPoint?: { __typename?: 'Coordinate', x: number, y: number } | null } | null }>, facetValues: Array<{ __typename?: 'FacetValueResult', count: number, facetValue: { __typename?: 'FacetValue', id: string, createdAt: any, updatedAt: any, name: string, facet: { __typename?: 'Facet', id: string, createdAt: any, updatedAt: any, name: string } } }> } };
 
 export type ProductSelectorSearchQueryVariables = Exact<{
   term: Scalars['String'];

+ 11 - 0
packages/admin-ui/src/lib/core/src/data/definitions/product-definitions.ts

@@ -485,6 +485,16 @@ export const SEARCH_PRODUCTS = gql`
                 enabled
                 productId
                 productName
+                slug
+                priceWithTax {
+                    ... on PriceRange {
+                        min
+                        max
+                    }
+                    ... on SinglePrice {
+                        value
+                    }
+                }
                 productAsset {
                     id
                     preview
@@ -493,6 +503,7 @@ export const SEARCH_PRODUCTS = gql`
                         y
                     }
                 }
+                currencyCode
                 productVariantId
                 productVariantName
                 productVariantAsset {

+ 3 - 2
packages/admin-ui/src/lib/core/src/shared/components/bulk-action-menu/bulk-action-menu.component.html

@@ -7,6 +7,7 @@
     >
         <clr-icon shape="file-group"></clr-icon>
         {{ 'common.with-selected' | translate: { count:selectionManager.selection.length } }}
+        <clr-icon shape="ellipsis-vertical"></clr-icon>
     </button>
     <vdr-dropdown-menu vdrPosition="bottom-left">
         <ng-container *ngIf="actions.length; else noActions">
@@ -33,10 +34,10 @@
     </vdr-dropdown-menu>
 </vdr-dropdown>
 <button
-    class="btn btn-sm btn-link"
+    class="button-small ml-2"
     (click)="clearSelection()"
     [class.hidden]="!selectionManager.selection?.length"
 >
+    <span>{{ 'common.clear-selection' | translate }}</span>
     <clr-icon shape="times"></clr-icon>
-    {{ 'common.clear-selection' | translate }}
 </button>

+ 6 - 0
packages/admin-ui/src/lib/core/src/shared/components/data-table-2/data-table-search.component.html

@@ -0,0 +1,6 @@
+<ng-template #vdrDt2Search>
+    <div class="search-wrapper">
+        <clr-icon shape="search" class="search-icon"></clr-icon>
+        <input [formControl]="searchTermControl" [placeholder]="searchTermPlaceholder" />
+    </div>
+</ng-template>

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

@@ -0,0 +1,14 @@
+.search-wrapper {
+    position: relative;
+    .search-icon {
+        position: absolute;
+        top: 50%;
+        transform: translateY(-50%);
+        left: 8px;
+        color: var(--color-weight-600);
+    }
+    > input {
+        padding-left: 32px !important;
+        width: 100%;
+    }
+}

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

@@ -0,0 +1,13 @@
+import { Component, ContentChild, Input, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { FormControl } from '@angular/forms';
+
+@Component({
+    selector: 'vdr-dt2-search',
+    templateUrl: `./data-table-search.component.html`,
+    styleUrls: ['./data-table-search.component.scss'],
+})
+export class DataTable2SearchComponent {
+    @Input() searchTermControl: FormControl<string>;
+    @Input() searchTermPlaceholder: string | undefined;
+    @ViewChild(TemplateRef, { static: true }) template: TemplateRef<any>;
+}

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

@@ -3,7 +3,7 @@
 </div>
 <table class="" [class.no-select]="disableSelect" [style.table-layout]="!items?.length ? 'fixed' : 'inherit'">
     <thead [class.items-selected]="selectionManager?.selection.length">
-        <tr>
+        <tr class="heading-row">
             <th *ngIf="selectionManager" class="align-middle">
                 <input
                     type="checkbox"
@@ -14,7 +14,6 @@
             </th>
             <th
                 *ngFor="let column of visibleColumns; last as isLast"
-                class="align-middle"
                 [class.expand]="column.expand"
             >
                 <div class="cell-content" [ngClass]="column.align">
@@ -25,12 +24,14 @@
                 </div>
             </th>
         </tr>
-        <tr *ngIf="searchTermControl || filters?.length">
+        <tr *ngIf="searchComponent || customSearchTemplate || filters?.length">
             <th [attr.colspan]="visibleColumns.length + (selectionManager ? 1 : 0)" class="filter-row">
-                <div class="search-wrapper">
+                <!--<div class="search-wrapper">
                     <clr-icon shape="search" class="search-icon"></clr-icon>
                     <input [formControl]="searchTermControl" [placeholder]="searchTermPlaceholder" />
-                </div>
+                </div>-->
+                <ng-container *ngTemplateOutlet="searchComponent?.template"></ng-container>
+                <ng-container *ngTemplateOutlet="customSearchTemplate"></ng-container>
                 <div class="filters">
                     <vdr-data-table-filters
                         *ngFor="let activeFilter of filters.getActiveFilters()"

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

@@ -3,13 +3,13 @@
     max-width: 100%;
     overflow: auto;
     position: relative;
+    margin-bottom: calc(var(--space-unit) * 4);
 }
 
 .bulk-actions {
-    position: absolute;
-    left: 50px;
-    top: 30px;
-    z-index: 2;
+    margin-top: 4px;
+    min-height: 40px;
+    padding-left: calc(var(--space-unit) * 4);
 }
 
 table {
@@ -22,31 +22,18 @@ table.no-select {
     user-select: none;
 }
 
-th {
-    font-size: var(--font-size-xs);
-    font-weight: 600;
-    text-transform: uppercase;
-    position: relative;
-}
-
 .column-picker {
     position: absolute;
     right: 2px;
     top: 7px;
 }
 
-.search-wrapper {
-    position: relative;
-    .search-icon {
-        position: absolute;
-        top: 50%;
-        transform: translateY(-50%);
-        left: 8px;
-        color: var(--color-weight-600);
-    }
-    > input {
-        padding-left: 32px !important;
-    }
+.heading-row th {
+    border-bottom: 1px solid var(--color-weight-200);
+    font-size: var(--font-size-xs);
+     font-weight: 600;
+     text-transform: uppercase;
+     position: relative;
 }
 
 .filter-row {
@@ -55,9 +42,10 @@ th {
     background-color: var(--color-weight-100);
     padding: calc(var(--space-unit) * 4) calc(var(--space-unit) * 4);
     box-shadow: inset -1px 6px 5px 0px rgb(165 165 165 / 8%);
-    border: 1px solid var(--color-weight-200);
+    border-bottom: 1px solid var(--color-weight-200);
     border-left-width: 0;
     border-right-width: 0;
+    text-align: initial;
     input {
         width: 100%;
     }
@@ -109,10 +97,6 @@ tbody tr:hover {
     }
 }
 
-thead.items-selected tr th {
-    color: transparent;
-}
-
 .selection-col {
     width: 24px;
 }

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

@@ -3,6 +3,7 @@ import {
     ChangeDetectionStrategy,
     ChangeDetectorRef,
     Component,
+    ContentChild,
     ContentChildren,
     EventEmitter,
     Input,
@@ -15,13 +16,14 @@ import {
     TemplateRef,
 } from '@angular/core';
 import { FormControl } from '@angular/forms';
-import { LocalStorageService } from '@vendure/admin-ui/core';
+import { BulkActionMenuComponent, LocalStorageService } from '@vendure/admin-ui/core';
 import { PaginationService } from 'ngx-pagination';
 import { Subscription } from 'rxjs';
 import { SelectionManager } from '../../../common/utilities/selection-manager';
 import { DataTableFilterCollection } from '../../../providers/data-table-filter/data-table-filter-collection';
 
 import { DataTable2ColumnComponent } from './data-table-column.component';
+import { DataTable2SearchComponent } from './data-table-search.component';
 
 /**
  * @description
@@ -97,13 +99,14 @@ export class DataTable2Component<T> implements AfterContentInit, OnChanges, OnIn
     @Input() totalItems: number;
     @Input() emptyStateLabel: string;
     @Input() selectionManager?: SelectionManager<T>;
-    @Input() searchTermControl?: FormControl<string>;
-    @Input() searchTermPlaceholder?: string;
     @Input() filters: DataTableFilterCollection;
     @Output() pageChange = new EventEmitter<number>();
     @Output() itemsPerPageChange = new EventEmitter<number>();
 
     @ContentChildren(DataTable2ColumnComponent) columns: QueryList<DataTable2ColumnComponent<T>>;
+    @ContentChild(DataTable2SearchComponent) searchComponent: DataTable2SearchComponent;
+    @ContentChild(BulkActionMenuComponent) bulkActionMenuComponent: BulkActionMenuComponent;
+    @ContentChild('vdrDt2CustomSearch') customSearchTemplate: TemplateRef<any>;
     @ContentChildren(TemplateRef) templateRefs: QueryList<TemplateRef<any>>;
     rowTemplate: TemplateRef<any>;
     currentStart: number;

+ 1 - 0
packages/admin-ui/src/lib/core/src/shared/components/page-title/page-title.component.scss

@@ -5,6 +5,7 @@
 .page-title {
     display: flex;
     gap: calc(var(--space-unit) * 2);
+    margin-bottom: calc(var(--space-unit) * 2);
     h1 {
         margin-top: 0;
         color: var(--color-weight-900);

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

@@ -40,6 +40,7 @@ import { CustomDetailComponentHostComponent } from './components/custom-detail-c
 import { CustomFieldControlComponent } from './components/custom-field-control/custom-field-control.component';
 import { CustomerLabelComponent } from './components/customer-label/customer-label.component';
 import { DataTable2ColumnComponent } from './components/data-table-2/data-table-column.component';
+import { DataTable2SearchComponent } from './components/data-table-2/data-table-search.component';
 import { DataTable2Component } from './components/data-table-2/data-table2.component';
 import { DataTableColumnComponent } from './components/data-table/data-table-column.component';
 import { DataTableComponent } from './components/data-table/data-table.component';
@@ -268,6 +269,7 @@ const DECLARATIONS = [
     DataTableFiltersComponent,
     DataTableFilterLabelComponent,
     DataTableColumnPickerComponent,
+    DataTable2SearchComponent,
 ];
 
 const DYNAMIC_FORM_INPUTS = [

+ 5 - 7
packages/admin-ui/src/lib/order/src/components/order-list/order-list.component.html

@@ -2,11 +2,7 @@
     <vdr-page-title>
         <vdr-action-bar-items locationId="order-list"></vdr-action-bar-items>
         <ng-container *ngIf="canCreateDraftOrder">
-            <a
-                class="btn"
-                *vdrIfPermissions="['CreateOrder']"
-                [routerLink]="['./draft/create']"
-            >
+            <a class="btn" *vdrIfPermissions="['CreateOrder']" [routerLink]="['./draft/create']">
                 <clr-icon shape="plus"></clr-icon>
                 {{ 'catalog.create-draft-order' | translate }}
             </a>
@@ -29,12 +25,14 @@
         [itemsPerPage]="itemsPerPage$ | async"
         [totalItems]="totalItems$ | async"
         [currentPage]="currentPage$ | async"
-        [searchTermControl]="searchControl"
-        [searchTermPlaceholder]="'order.search-by-order-filters' | translate"
         [filters]="filters"
         (pageChange)="setPageNumber($event)"
         (itemsPerPageChange)="setItemsPerPage($event)"
     >
+        <vdr-dt2-search
+            [searchTermControl]="searchControl"
+            [searchTermPlaceholder]="'order.search-by-order-filters' | translate"
+        ></vdr-dt2-search>
         <vdr-dt2-column [heading]="'common.code' | translate" [optional]="false">
             <ng-template let-order="item">
                 <a class="button-ghost" [routerLink]="['./', order.id]"