ACA-3426 - Search Headers for Document List (#5800)

* [ACA-3426] Move filter-menu inside search and renamed as search-header

* [ACA-3426] adf-search-header removed from document-list and implemented in app-files

* [ACA-3426] Allow custom header filters inside document-list

* [ACA-3426] Decouple search from the document-list

* [ACA-3409] NodePaging ouputed to the DL

* [ACA-3426] - fixed injection for service

* Dev baptiste aca 3430 (#5773)

* [ACA-3430] Add style to filter and hide action buttons from facet widgets

* [ACA-3430] Update eventEmitter created in the DL and create  unit tests for the search-header

Co-authored-by: BaptisteMahe <mahe.baptiste.19@gmail.com>

* [ACA-3426] - added parent for service

* [ACA-3426] - added parent for service - fixed method

* [ACA-3426] Revert update EventEmitter inside DL

* [ACA-3436] Use of the node input instead of nodeUpdate mehtod

* [ACA-3426] Add clear behaviour to search-header

* [ACA-3426] Remove useless update exposition

* [ACA-3426] Update filter button styles and padding inside the filter menu

* [ACA-3443] Propagate filters states through DL and datatable to avoid hiding the header

* [ACA-3426] Refactor showHeader logic and use it for the filters

* [ACA-3426] - fixed pagination for filter result

* [ACA-3426] - fixed messed files after rebase

* [ACA-3426] - added simplified config version

* [ACA-3426] - enabling created by filter

* [ACA-3426] Fix search-date-range apply method

* [ACA-3426] Fix loading style and default showHeaderMode

* [ACA-3426] Changed showHedaer default to always

* [ACA-3426] - stabilised the feature and added injection token

* [ACA-3426] Add unit test for showHeader new behaviour

* [ACA-3426] Add documentation to search-header

* [ACA-3426] - added parent filtering for special folders

* [ACA-3426] - added unit test for search header

* [ACA-3426] - fixed search fitler behavour

* [ACA-3426] - fixed search result inject service

* [ACA-3426] - fixed search result inject service for search sorting

* [ACA-3426] - fixed title for matching selector

* [ACA-3426] - fixed app config with missing search widget

* Update search-header.component.md

Co-authored-by: BaptisteMahe <mahe.baptiste.19@gmail.com>
Co-authored-by: Eugenio Romano <eromano@users.noreply.github.com>
This commit is contained in:
Vito
2020-06-22 09:24:57 +01:00
committed by GitHub
parent 5a0ba6666d
commit 29d953e2d1
54 changed files with 1888 additions and 544 deletions

View File

@@ -434,6 +434,176 @@
]
}
},
"search-headers": {
"app:fields": [
"cm:name",
"cm:title",
"cm:description",
"ia:whatEvent",
"ia:descriptionEvent",
"lnk:title",
"lnk:description",
"TEXT",
"TAG"
],
"categories": [
{
"id": "queryName",
"name": "Name",
"columnKey": "name",
"enabled": true,
"expanded": true,
"component": {
"selector": "text",
"settings": {
"pattern": "cm:name:'(.*?)'",
"field": "cm:name",
"placeholder": "Enter the name"
}
}
},
{
"id": "checkList",
"name": "Check List",
"columnKey":"$thumbnail",
"enabled": true,
"component": {
"selector": "check-list",
"settings": {
"pageSize": 5,
"operator": "OR",
"options": [
{
"name": "Folder",
"value": "TYPE:'cm:folder'"
},
{
"name": "Document",
"value": "TYPE:'cm:content'"
}
]
}
}
},
{
"id": "contentSizeRange",
"name": "Content Size (range)",
"enabled": true,
"component": {
"selector": "number-range",
"settings": {
"field": "cm:content.size",
"format": "[{FROM} TO {TO}]"
}
}
},
{
"id": "contentSize",
"name": "SEARCH.CATEGORIES.SIZE",
"columnKey":"content.sizeInBytes",
"enabled": true,
"component": {
"selector": "check-list",
"settings": {
"options": [
{
"name": "Small",
"value": "content.size:[0 TO 1048576>"
},
{
"name": "Medium",
"value": "content.size:[1048576 TO 52428800]"
},
{
"name": "Large",
"value": "content.size:<52428800 TO 524288000]"
},
{
"name": "Huge",
"value": "content.size:<524288000 TO MAX]"
}
]
}
}
},
{
"id": "createdDateRange",
"name": "Created Date (range)",
"columnKey": "createdAt",
"enabled": true,
"component": {
"selector": "date-range",
"settings": {
"field": "cm:created",
"dateFormat": "DD-MMM-YY",
"maxDate": "today"
}
}
}
],
"highlight": {
"prefix": " ",
"postfix": " ",
"mergeContiguous": true,
"fields": [
{
"field": "cm:title"
},
{
"field": "description",
"prefix": "(",
"postfix": ")"
}
]
},
"sorting": {
"options": [
{
"key": "name",
"label": "Name",
"type": "FIELD",
"field": "cm:name",
"ascending": true
},
{
"key": "content.sizeInBytes",
"label": "Size",
"type": "FIELD",
"field": "content.size",
"ascending": true
},
{
"key": "createdByUser",
"label": "Author",
"type": "FIELD",
"field": "cm:creator",
"ascending": true
},
{
"key": "createdAt",
"label": "Created",
"type": "FIELD",
"field": "cm:created",
"ascending": true
},
{
"key": "score",
"label": "Relevance",
"type": "FIELD",
"field": "score",
"ascending": false
}
],
"defaults": [
{
"key": "score",
"type": "FIELD",
"field": "score",
"ascending": false
}
]
}
},
"pagination": {
"size": 20,
"supportedPageSizes": [

View File

@@ -102,6 +102,7 @@ import localePl from '@angular/common/locales/pl';
import localeFi from '@angular/common/locales/fi';
import localeDa from '@angular/common/locales/da';
import localeSv from '@angular/common/locales/sv';
import { FilteredSearchComponent } from './components/files/filtered-search.component';
registerLocaleData(localeFr);
registerLocaleData(localeDe);
@@ -158,6 +159,7 @@ registerLocaleData(localeSv);
FormNodeViewerComponent,
AppsViewComponent,
FilesComponent,
FilteredSearchComponent,
FormComponent,
FormListComponent,
VersionManagerDialogAdapterComponent,

View File

@@ -59,6 +59,7 @@ import { FormCloudDemoComponent } from './components/app-layout/cloud/form-demo/
import { ConfirmDialogExampleComponent } from './components/confirm-dialog/confirm-dialog-example.component';
import { DemoErrorComponent } from './components/error/demo-error.component';
import { TaskHeaderCloudDemoComponent } from './components/cloud/task-header-cloud-demo.component';
import { FilteredSearchComponent } from './components/files/filtered-search.component';
export const appRoutes: Routes = [
{ path: 'login', loadChildren: 'app/components/login/login.module#AppLoginModule' },
{ path: 'logout', component: LogoutComponent },
@@ -251,6 +252,21 @@ export const appRoutes: Routes = [
component: FilesComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'filtered-search',
component: FilteredSearchComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'filtered-search/:id',
component: FilteredSearchComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'filtered-search/:id/display/:mode',
component: FilteredSearchComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'extensions/document-list/presets',
canActivate: [AuthGuardEcm],

View File

@@ -40,6 +40,7 @@ export class AppLayoutComponent implements OnInit, OnDestroy {
]
},
{ href: '/files', icon: 'folder_open', title: 'APP_LAYOUT.CONTENT_SERVICES' },
{ href: '/filtered-search', icon: 'rowing', title: 'APP_LAYOUT.FILTERED_SEARCH' },
{ href: '/breadcrumb', icon: 'label', title: 'APP_LAYOUT.BREADCRUMB' },
{ href: '/notifications', icon: 'alarm', title: 'APP_LAYOUT.NOTIFICATIONS' },
{ href: '/card-view', icon: 'view_headline', title: 'APP_LAYOUT.CARD_VIEW' },

View File

@@ -244,6 +244,17 @@
(folderChange)="onFolderChange($event)"
(permissionError)="handlePermissionError($event)"
(name-click)="documentList.onNodeDblClick($event.detail?.node)">
<adf-custom-header-filter-template *ngIf="enableCustomHeaderFilter">
<ng-template let-col>
<adf-search-header [col]="col"
[currentFolderNodeId]="currentFolderId"
[maxItems]="pagination?.maxItems"
[skipCount]="pagination?.skipCount"
(update)="onFilterUpdate($event)"
(clear)="onAllFilterCleared()">
</adf-search-header>
</ng-template>
</adf-custom-header-filter-template>
<adf-custom-no-permission-template *ngIf="enableCustomPermissionMessage">
<h1>You don't have permissions</h1>
</adf-custom-no-permission-template>

View File

@@ -28,7 +28,7 @@ import {
AlfrescoApiService, AuthenticationService, AppConfigService, AppConfigValues, ContentService, TranslationService,
FileUploadEvent, FolderCreatedEvent, LogService, NotificationService,
UploadService, DataRow, UserPreferencesService,
PaginationComponent, FormValues, DisplayMode, InfinitePaginationComponent, HighlightDirective,
PaginationComponent, FormValues, DisplayMode, ShowHeaderMode, InfinitePaginationComponent, HighlightDirective,
SharedLinksApiService
} from '@alfresco/adf-core';
@@ -104,7 +104,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
showSettingsPanel = true;
@Input()
showHeader = true;
showHeader: string = ShowHeaderMode.Always;
@Input()
selectionMode = 'multiple';
@@ -157,6 +157,12 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
@Input()
searchTerm = '';
@Input()
navigationRoute = '/files';
@Input()
enableCustomHeaderFilter = false;
@Output()
documentListReady: EventEmitter<any> = new EventEmitter();
@@ -195,10 +201,12 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
stickyHeader: boolean;
warnOnMultipleUploads = false;
thumbnails = false;
enableCustomPermissionMessage = false;
enableMediumTimeFormat = false;
displayEmptyMetadata = false;
hyperlinkNavigation = false;
filtersStates: any[] = [];
constructor(private notificationService: NotificationService,
private uploadService: UploadService,
@@ -361,7 +369,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
}
onFolderChange($event) {
this.router.navigate(['/files', $event.value.id, 'display', this.displayMode]);
this.router.navigate([this.navigationRoute, $event.value.id, 'display', this.displayMode]);
}
handlePermissionError(event: any) {
@@ -519,22 +527,32 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
onChangePageSize(event: Pagination): void {
this.preference.paginationSize = event.maxItems;
this.pagination.maxItems = event.maxItems;
this.pagination.skipCount = event.skipCount;
this.changedPageSize.emit(event);
}
onChangePageNumber(event: Pagination): void {
this.pagination.maxItems = event.maxItems;
this.pagination.skipCount = event.skipCount;
this.changedPageNumber.emit(event);
}
onNextPage(event: Pagination): void {
this.pagination.maxItems = event.maxItems;
this.pagination.skipCount = event.skipCount;
this.turnedNextPage.emit(event);
}
loadNextBatch(event: Pagination): void {
this.pagination.maxItems = event.maxItems;
this.pagination.skipCount = event.skipCount;
this.loadNext.emit(event);
}
onPrevPage(event: Pagination): void {
this.pagination.maxItems = event.maxItems;
this.pagination.skipCount = event.skipCount;
this.turnedPreviousPage.emit(event);
}
@@ -630,4 +648,14 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy {
}
return '';
}
onFilterUpdate(newNodePaging: NodePaging) {
this.nodeResult = newNodePaging;
}
onAllFilterCleared() {
this.documentList.node = null;
this.documentList.reload();
}
}

View File

@@ -0,0 +1,8 @@
<app-files-component [sortingMode]="'server'"
[showRecentFiles]="false"
[showSitePicker]="true"
[showSettingsPanel]="false"
[navigationRoute]="navigationRoute"
[currentFolderId]="currentFolderId"
[enableCustomHeaderFilter]="true">
</app-files-component>

View File

@@ -0,0 +1,42 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Optional } from '@angular/core';
import { SEARCH_QUERY_SERVICE_TOKEN, SearchHeaderQueryBuilderService } from '@alfresco/adf-content-services';
import { ActivatedRoute, Params } from '@angular/router';
@Component({
selector: 'app-filtered-search-component',
templateUrl: './filtered-search.component.html',
providers: [{ provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchHeaderQueryBuilderService}]
})
export class FilteredSearchComponent {
navigationRoute = '/filtered-search';
currentFolderId = '-my-';
constructor(@Optional() private route: ActivatedRoute) {
if (this.route) {
this.route.params.forEach((params: Params) => {
if (params['id'] && this.currentFolderId !== params['id']) {
this.currentFolderId = params['id'];
}
});
}
}
}

View File

@@ -15,10 +15,10 @@
* limitations under the License.
*/
import { Component, OnInit, Optional, OnDestroy } from '@angular/core';
import { Component, OnInit, Optional, OnDestroy, Inject } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { Pagination, ResultSetPaging } from '@alfresco/js-api';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
import { SearchQueryBuilderService, SEARCH_QUERY_SERVICE_TOKEN } from '@alfresco/adf-content-services';
import { UserPreferencesService, SearchService, AppConfigService } from '@alfresco/adf-core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@@ -27,7 +27,7 @@ import { takeUntil } from 'rxjs/operators';
selector: 'app-search-result-component',
templateUrl: './search-result.component.html',
styleUrls: ['./search-result.component.scss'],
providers: [SearchService, SearchQueryBuilderService]
providers: [SearchService, { provide: SEARCH_QUERY_SERVICE_TOKEN, useClass: SearchQueryBuilderService}]
})
export class SearchResultComponent implements OnInit, OnDestroy {
@@ -44,7 +44,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
constructor(public router: Router,
private config: AppConfigService,
private preferences: UserPreferencesService,
private queryBuilder: SearchQueryBuilderService,
@Inject(SEARCH_QUERY_SERVICE_TOKEN) private queryBuilder: SearchQueryBuilderService,
@Optional() private route: ActivatedRoute) {
queryBuilder.paging = {
maxItems: this.preferences.paginationSize,