[ACA-19] Library Search Results (#783)

* [ACA-19] libraries results page

* [ACA-19] libraries search query builder service + trigger action on search option select

* [ACA-19] remove sorting

* [ACA-19] extension - set custom columns for search libraries results

* [ACA-19] add role column

* [ACA-19] adapt text

* [ACA-19] reformat with Prettier

* [ACA-19] fix unit tests

* [ACA-19] reformat with Prettier

* [ACA-19] some unit tests & code cleanup

* [ACA-19] fix navigation

* [ACA-19] remove duplicates

* [ACA-19] unit test
This commit is contained in:
Suzana Dirla
2018-11-08 14:22:09 +02:00
committed by Denys Vuika
parent cb3754e29d
commit 1e3136332e
14 changed files with 649 additions and 12 deletions

View File

@@ -29,6 +29,7 @@ import { FilesComponent } from './components/files/files.component';
import { LibrariesComponent } from './components/libraries/libraries.component'; import { LibrariesComponent } from './components/libraries/libraries.component';
import { GenericErrorComponent } from './components/common/generic-error/generic-error.component'; import { GenericErrorComponent } from './components/common/generic-error/generic-error.component';
import { SearchResultsComponent } from './components/search/search-results/search-results.component'; import { SearchResultsComponent } from './components/search/search-results/search-results.component';
import { SearchLibrariesResultsComponent } from './components/search/search-libraries-results/search-libraries-results.component';
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
import { AppAuthGuard } from './guards/auth.guard'; import { AppAuthGuard } from './guards/auth.guard';
import { AppSharedRuleGuard } from './guards/shared.guard'; import { AppSharedRuleGuard } from './guards/shared.guard';
@@ -213,7 +214,7 @@ export const APP_ROUTES: Routes = [
children: [ children: [
{ {
path: '', path: '',
component: SearchResultsComponent, component: SearchLibrariesResultsComponent,
data: { data: {
title: 'APP.BROWSE.SEARCH.TITLE', title: 'APP.BROWSE.SEARCH.TITLE',
reuse: true reuse: true

View File

@@ -26,8 +26,10 @@
</app-search-input-control> </app-search-input-control>
<div id="search-options"> <div id="search-options">
<mat-checkbox *ngFor="let option of searchOptions" <mat-checkbox *ngFor="let option of searchOptions"
id="{{ option.id }}"
[(ngModel)]="option.value" [(ngModel)]="option.value"
[disabled]="option.shouldDisable()" [disabled]="option.shouldDisable()"
(change)="onOptionChange()"
(click)="$event.stopPropagation()"> (click)="$event.stopPropagation()">
{{ option.key | translate }} {{ option.key | translate }}
</mat-checkbox> </mat-checkbox>

View File

@@ -37,6 +37,8 @@ import { AppTestingModule } from '../../../testing/app-testing.module';
import { Actions, ofType } from '@ngrx/effects'; import { Actions, ofType } from '@ngrx/effects';
import { SEARCH_BY_TERM, SearchByTermAction } from '../../../store/actions'; import { SEARCH_BY_TERM, SearchByTermAction } from '../../../store/actions';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
describe('SearchInputComponent', () => { describe('SearchInputComponent', () => {
let fixture: ComponentFixture<SearchInputComponent>; let fixture: ComponentFixture<SearchInputComponent>;
@@ -47,7 +49,8 @@ describe('SearchInputComponent', () => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AppTestingModule], imports: [AppTestingModule],
declarations: [SearchInputComponent], declarations: [SearchInputComponent],
schemas: [NO_ERRORS_SCHEMA] schemas: [NO_ERRORS_SCHEMA],
providers: [SearchQueryBuilderService, SearchLibrariesQueryBuilderService]
}) })
.compileComponents() .compileComponents()
.then(() => { .then(() => {

View File

@@ -38,6 +38,14 @@ import { Store } from '@ngrx/store';
import { AppStore } from '../../../store/states/app.state'; import { AppStore } from '../../../store/states/app.state';
import { SearchByTermAction } from '../../../store/actions'; import { SearchByTermAction } from '../../../store/actions';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { SearchLibrariesQueryBuilderService } from '../search-libraries-results/search-libraries-query-builder.service';
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
export enum SearchOptionIds {
Files = 'files',
Folders = 'folders',
Libraries = 'libraries'
}
@Component({ @Component({
selector: 'aca-search-input', selector: 'aca-search-input',
@@ -51,18 +59,21 @@ export class SearchInputComponent implements OnInit {
navigationTimer: any; navigationTimer: any;
searchedWord = null; searchedWord = null;
searchOptions: any = [ searchOptions: Array<any> = [
{ {
id: SearchOptionIds.Files,
key: 'SEARCH.INPUT.FILES', key: 'SEARCH.INPUT.FILES',
value: false, value: false,
shouldDisable: this.isLibrariesChecked.bind(this) shouldDisable: this.isLibrariesChecked.bind(this)
}, },
{ {
id: SearchOptionIds.Folders,
key: 'SEARCH.INPUT.FOLDERS', key: 'SEARCH.INPUT.FOLDERS',
value: false, value: false,
shouldDisable: this.isLibrariesChecked.bind(this) shouldDisable: this.isLibrariesChecked.bind(this)
}, },
{ {
id: SearchOptionIds.Libraries,
key: 'SEARCH.INPUT.LIBRARIES', key: 'SEARCH.INPUT.LIBRARIES',
value: false, value: false,
shouldDisable: this.isContentChecked.bind(this) shouldDisable: this.isContentChecked.bind(this)
@@ -72,7 +83,12 @@ export class SearchInputComponent implements OnInit {
@ViewChild('searchInputControl') @ViewChild('searchInputControl')
searchInputControl: SearchInputControlComponent; searchInputControl: SearchInputControlComponent;
constructor(private router: Router, private store: Store<AppStore>) {} constructor(
private librariesQueryBuilder: SearchLibrariesQueryBuilderService,
private queryBuilder: SearchQueryBuilderService,
private router: Router,
private store: Store<AppStore>
) {}
ngOnInit() { ngOnInit() {
this.showInputValue(); this.showInputValue();
@@ -89,7 +105,7 @@ export class SearchInputComponent implements OnInit {
showInputValue() { showInputValue() {
this.searchedWord = ''; this.searchedWord = '';
if (this.onSearchResults) { if (this.onSearchResults || this.onLibrariesSearchResults) {
const urlTree: UrlTree = this.router.parseUrl(this.router.url); const urlTree: UrlTree = this.router.parseUrl(this.router.url);
const urlSegmentGroup: UrlSegmentGroup = const urlSegmentGroup: UrlSegmentGroup =
urlTree.root.children[PRIMARY_OUTLET]; urlTree.root.children[PRIMARY_OUTLET];
@@ -141,14 +157,57 @@ export class SearchInputComponent implements OnInit {
}, 1000); }, 1000);
} }
onOptionChange() {
if (this.searchedWord) {
if (this.isLibrariesChecked()) {
if (this.onLibrariesSearchResults) {
this.librariesQueryBuilder.update();
} else {
this.store.dispatch(
new SearchByTermAction(this.searchedWord, this.searchOptions)
);
}
} else if (this.isContentChecked()) {
if (this.onSearchResults) {
// TODO: send here data to this.queryBuilder to be able to search for files/folders
this.queryBuilder.update();
} else {
this.store.dispatch(
new SearchByTermAction(this.searchedWord, this.searchOptions)
);
}
}
}
}
get onLibrariesSearchResults() {
return this.router.url.indexOf('/search-libraries') === 0;
}
get onSearchResults() { get onSearchResults() {
return this.router.url.indexOf('/search') === 0; return (
!this.onLibrariesSearchResults && this.router.url.indexOf('/search') === 0
);
}
isFilesChecked(): boolean {
return this.isOptionChecked(SearchOptionIds.Files);
}
isFoldersChecked(): boolean {
return this.isOptionChecked(SearchOptionIds.Folders);
} }
isLibrariesChecked(): boolean { isLibrariesChecked(): boolean {
return this.searchOptions[2].value; return this.isOptionChecked(SearchOptionIds.Libraries);
} }
isOptionChecked(optionId: string): boolean {
const libItem = this.searchOptions.find(item => item.id === optionId);
return !!libItem && libItem.value;
}
isContentChecked(): boolean { isContentChecked(): boolean {
return this.searchOptions[0].value || this.searchOptions[1].value; return this.isFilesChecked() || this.isFoldersChecked();
} }
} }

View File

@@ -0,0 +1,96 @@
/*!
* @license
* Copyright 2016 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 { TestBed } from '@angular/core/testing';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { AlfrescoApiService } from '@alfresco/adf-core';
import { SearchLibrariesQueryBuilderService } from './search-libraries-query-builder.service';
describe('SearchLibrariesQueryBuilderService', () => {
let apiService: AlfrescoApiService;
let builder: SearchLibrariesQueryBuilderService;
let queriesApi;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule]
});
apiService = TestBed.get(AlfrescoApiService);
apiService.reset();
queriesApi = apiService.getInstance().core.queriesApi;
builder = new SearchLibrariesQueryBuilderService(apiService);
});
it('should have empty user query by default', () => {
expect(builder.userQuery).toBe('');
});
it('should trim user query value', () => {
builder.userQuery = ' something ';
expect(builder.userQuery).toEqual('something');
});
it('should build query and raise an event on update', async () => {
const query = {};
spyOn(builder, 'buildQuery').and.returnValue(query);
let eventArgs = null;
builder.updated.subscribe(args => (eventArgs = args));
await builder.update();
expect(eventArgs).toBe(query);
});
it('should build query and raise an event on execute', async () => {
const data = {};
spyOn(queriesApi, 'findSites').and.returnValue(Promise.resolve(data));
const query = {};
spyOn(builder, 'buildQuery').and.returnValue(query);
let eventArgs = null;
builder.executed.subscribe(args => (eventArgs = args));
await builder.execute();
expect(eventArgs).toBe(data);
});
it('should require a query fragment to build query', () => {
const compiled = builder.buildQuery();
expect(compiled).toBeNull();
});
it('should build query when there is a useQuery value', () => {
const searchedTerm = 'test';
builder.userQuery = searchedTerm;
const compiled = builder.buildQuery();
expect(compiled.term).toBe(searchedTerm);
});
it('should use pagination settings', () => {
const searchedTerm = 'test';
builder.paging = { maxItems: 5, skipCount: 5 };
builder.userQuery = searchedTerm;
const compiled = builder.buildQuery();
expect(compiled.opts).toEqual({ maxItems: 5, skipCount: 5 });
});
});

View File

@@ -0,0 +1,86 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { AlfrescoApiService } from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { SitePaging } from 'alfresco-js-api';
import { Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class SearchLibrariesQueryBuilderService {
private _userQuery = '';
updated: Subject<any> = new Subject();
executed: Subject<any> = new Subject();
paging: { maxItems?: number; skipCount?: number } = null;
get userQuery(): string {
return this._userQuery;
}
set userQuery(value: string) {
this._userQuery = value ? value.trim() : '';
}
constructor(private alfrescoApiService: AlfrescoApiService) {}
update(): void {
const query = this.buildQuery();
this.updated.next(query);
}
async execute() {
const query = this.buildQuery();
if (query) {
const data = await this.findLibraries(query);
this.executed.next(data);
}
}
buildQuery(): any {
const query = this.userQuery;
if (query) {
const resultQuery = {
term: query,
opts: {
skipCount: this.paging && this.paging.skipCount,
maxItems: this.paging && this.paging.maxItems
}
};
return resultQuery;
}
return null;
}
private findLibraries(libraryQuery: { term; opts }): Promise<SitePaging> {
return this.alfrescoApiService
.getInstance()
.core.queriesApi.findSites(libraryQuery.term, libraryQuery.opts)
.catch(() => ({ list: { pagination: { totalItems: 0 }, entries: [] } }));
}
}

View File

@@ -0,0 +1,99 @@
<app-page-layout>
<app-page-layout-header>
<adf-breadcrumb root="APP.BROWSE.SEARCH_LIBRARIES.TITLE">
</adf-breadcrumb>
<adf-toolbar class="inline">
<ng-container *ngFor="let entry of actions; trackBy: trackByActionId">
<aca-toolbar-action [actionRef]="entry"></aca-toolbar-action>
</ng-container>
</adf-toolbar>
</app-page-layout-header>
<app-page-layout-content>
<div class="main-content">
<div class="adf-search-results">
<div class="adf-search-results__content">
<mat-progress-bar
*ngIf="isLoading"
color="primary"
mode="indeterminate">
</mat-progress-bar>
<div class="adf-search-results__content-header content" *ngIf="data?.list.entries.length">
<div class="content__side--left">
<div class="adf-search-results--info-text">{{ 'APP.BROWSE.SEARCH_LIBRARIES.FOUND_RESULTS' | translate: { number: totalResults } }}</div>
</div>
</div>
<adf-document-list
#documentList
acaDocumentList
[showHeader]="true"
[selectionMode]="'single'"
[sorting]="[ 'name', 'asc' ]"
[node]="data"
(node-dblclick)="navigateTo($event.detail?.node)"
(name-click)="navigateTo($event.detail?.node)">
<data-columns>
<ng-container *ngFor="let column of columns; trackBy: trackById">
<ng-container *ngIf="column.template && !(column.desktopOnly && isSmallScreen)">
<data-column
[key]="column.key"
[title]="column.title"
[type]="column.type"
[format]="column.format"
[class]="column.class"
[sortable]="column.sortable">
<ng-template let-context>
<app-dynamic-column
[id]="column.template"
[context]="context">
</app-dynamic-column>
</ng-template>
</data-column>
</ng-container>
<ng-container *ngIf="!column.template && !(column.desktopOnly && isSmallScreen)">
<data-column
[key]="column.key"
[title]="column.title"
[type]="column.type"
[format]="column.format"
[class]="column.class"
[sortable]="column.sortable">
</data-column>
</ng-container>
</ng-container>
</data-columns>
<empty-folder-content>
<ng-template>
<ng-container *ngIf="data">
<div class="empty-search__block">
<p class="empty-search__text">
{{ 'APP.BROWSE.SEARCH.NO_RESULTS' | translate }}
</p>
</div>
</ng-container>
</ng-template>
</empty-folder-content>
</adf-document-list>
<adf-pagination *ngIf="!documentList.isEmpty()"
acaPagination
[target]="documentList"
(change)="onPaginationChanged($event)">
</adf-pagination>
</div>
</div>
</div>
<div class="sidebar" *ngIf="infoDrawerOpened$ | async">
<aca-info-drawer [node]="selection.last"></aca-info-drawer>
</div>
</app-page-layout-content>
</app-page-layout>

View File

@@ -0,0 +1,42 @@
@import 'mixins';
.adf-search-results {
@include flex-row;
&__content {
@include flex-column;
border-left: 1px solid #eee;
}
&__content-header {
display: flex;
padding: 0 25px 0 25px;
flex-direction: row;
align-items: center;
border-bottom: 1px solid #eee;
}
&--info-text {
flex: 1;
font-size: 16px;
color: rgba(0, 0, 0, 0.54);
}
.text--bold {
font-weight: 600;
}
.content {
@include flex-row;
flex: unset;
height: unset;
padding-top: 8px;
padding-bottom: 8px;
flex-wrap: wrap;
&__side--left {
@include flex-column;
height: unset;
}
}
}

View File

@@ -0,0 +1,38 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppTestingModule } from '../../../testing/app-testing.module';
import { AppConfigPipe, DataTableComponent } from '@alfresco/adf-core';
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { SearchLibrariesResultsComponent } from './search-libraries-results.component';
import { SearchLibrariesQueryBuilderService } from './search-libraries-query-builder.service';
import { DocumentListComponent } from '@alfresco/adf-content-services';
describe('SearchLibrariesResultsComponent', () => {
let component: SearchLibrariesResultsComponent;
let fixture: ComponentFixture<SearchLibrariesResultsComponent>;
const emptyPage = { list: { pagination: { totalItems: 0 }, entries: [] } };
beforeEach(() => {
TestBed.configureTestingModule({
imports: [AppTestingModule],
declarations: [
DataTableComponent,
DocumentListComponent,
SearchLibrariesResultsComponent,
AppConfigPipe
],
schemas: [NO_ERRORS_SCHEMA],
providers: [SearchLibrariesQueryBuilderService]
});
fixture = TestBed.createComponent(SearchLibrariesResultsComponent);
component = fixture.componentInstance;
});
it('should show empty page by default', async () => {
spyOn(component, 'onSearchResultLoaded').and.callThrough();
fixture.detectChanges();
expect(component.onSearchResultLoaded).toHaveBeenCalledWith(emptyPage);
});
});

View File

@@ -0,0 +1,148 @@
/*!
* @license
* Alfresco Example Content Application
*
* Copyright (C) 2005 - 2018 Alfresco Software Limited
*
* This file is part of the Alfresco Example Content Application.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
import { Component, OnInit } from '@angular/core';
import { NodePaging, Pagination, SiteEntry } from 'alfresco-js-api';
import { ActivatedRoute, Params } from '@angular/router';
import { PageComponent } from '../../page.component';
import { Store } from '@ngrx/store';
import { AppStore } from '../../../store/states/app.state';
import { NavigateLibraryAction } from '../../../store/actions';
import { AppExtensionService } from '../../../extensions/extension.service';
import { ContentManagementService } from '../../../services/content-management.service';
import { SearchLibrariesQueryBuilderService } from './search-libraries-query-builder.service';
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
@Component({
selector: 'aca-search-results',
templateUrl: './search-libraries-results.component.html',
styleUrls: ['./search-libraries-results.component.scss'],
providers: [SearchLibrariesQueryBuilderService]
})
export class SearchLibrariesResultsComponent extends PageComponent
implements OnInit {
isSmallScreen = false;
searchedWord: string;
queryParamName = 'q';
data: NodePaging;
totalResults = 0;
isLoading = false;
columns: any[] = [];
constructor(
private breakpointObserver: BreakpointObserver,
private librariesQueryBuilder: SearchLibrariesQueryBuilderService,
private route: ActivatedRoute,
store: Store<AppStore>,
extensions: AppExtensionService,
content: ContentManagementService
) {
super(store, extensions, content);
librariesQueryBuilder.paging = {
skipCount: 0,
maxItems: 25
};
}
ngOnInit() {
super.ngOnInit();
this.columns = this.extensions.documentListPresets.searchLibraries || [];
this.subscriptions.push(
this.librariesQueryBuilder.updated.subscribe(() => {
this.isLoading = true;
this.librariesQueryBuilder.execute();
}),
this.librariesQueryBuilder.executed.subscribe(data => {
this.librariesQueryBuilder.paging.skipCount = 0;
this.onSearchResultLoaded(data);
this.isLoading = false;
}),
this.breakpointObserver
.observe([Breakpoints.HandsetPortrait, Breakpoints.HandsetLandscape])
.subscribe(result => {
this.isSmallScreen = result.matches;
})
);
if (this.route) {
this.route.params.forEach((params: Params) => {
this.searchedWord = params.hasOwnProperty(this.queryParamName)
? params[this.queryParamName]
: null;
const query = this.formatSearchQuery(this.searchedWord);
if (query && query.length > 1) {
this.librariesQueryBuilder.userQuery = query;
this.librariesQueryBuilder.update();
} else {
this.librariesQueryBuilder.userQuery = null;
this.librariesQueryBuilder.executed.next({
list: { pagination: { totalItems: 0 }, entries: [] }
});
}
});
}
}
private formatSearchQuery(userInput: string) {
if (!userInput) {
return null;
}
return userInput.trim();
}
onSearchResultLoaded(nodePaging: NodePaging) {
this.data = nodePaging;
this.totalResults = this.getNumberOfResults();
}
getNumberOfResults() {
if (this.data && this.data.list && this.data.list.pagination) {
return this.data.list.pagination.totalItems;
}
return 0;
}
onPaginationChanged(pagination: Pagination) {
this.librariesQueryBuilder.paging = {
maxItems: pagination.maxItems,
skipCount: pagination.skipCount
};
this.librariesQueryBuilder.update();
}
navigateTo(node: SiteEntry) {
if (node && node.entry && node.entry.guid) {
this.store.dispatch(new NavigateLibraryAction(node.entry.guid));
}
}
}

View File

@@ -29,6 +29,7 @@ import { CoreModule } from '@alfresco/adf-core';
import { ContentModule } from '@alfresco/adf-content-services'; import { ContentModule } from '@alfresco/adf-content-services';
import { SearchResultsComponent } from './search-results/search-results.component'; import { SearchResultsComponent } from './search-results/search-results.component';
import { SearchResultsRowComponent } from './search-results-row/search-results-row.component'; import { SearchResultsRowComponent } from './search-results-row/search-results-row.component';
import { SearchLibrariesResultsComponent } from './search-libraries-results/search-libraries-results.component';
import { AppInfoDrawerModule } from '../info-drawer/info.drawer.module'; import { AppInfoDrawerModule } from '../info-drawer/info.drawer.module';
import { AppToolbarModule } from '../toolbar/toolbar.module'; import { AppToolbarModule } from '../toolbar/toolbar.module';
import { AppCommonModule } from '../common/common.module'; import { AppCommonModule } from '../common/common.module';
@@ -46,7 +47,15 @@ import { AppLayoutModule } from '../layout/layout.module';
DirectivesModule, DirectivesModule,
AppLayoutModule AppLayoutModule
], ],
declarations: [SearchResultsComponent, SearchResultsRowComponent], declarations: [
exports: [SearchResultsComponent, SearchResultsRowComponent] SearchResultsComponent,
SearchLibrariesResultsComponent,
SearchResultsRowComponent
],
exports: [
SearchResultsComponent,
SearchLibrariesResultsComponent,
SearchResultsRowComponent
]
}) })
export class AppSearchResultsModule {} export class AppSearchResultsModule {}

View File

@@ -79,13 +79,15 @@ export class AppExtensionService implements RuleContext {
recent: Array<DocumentListPresetRef>; recent: Array<DocumentListPresetRef>;
favorites: Array<DocumentListPresetRef>; favorites: Array<DocumentListPresetRef>;
trashcan: Array<DocumentListPresetRef>; trashcan: Array<DocumentListPresetRef>;
searchLibraries: Array<DocumentListPresetRef>;
} = { } = {
files: [], files: [],
libraries: [], libraries: [],
shared: [], shared: [],
recent: [], recent: [],
favorites: [], favorites: [],
trashcan: [] trashcan: [],
searchLibraries: []
}; };
selection: SelectionState; selection: SelectionState;
@@ -163,7 +165,8 @@ export class AppExtensionService implements RuleContext {
shared: this.getDocumentListPreset(config, 'shared'), shared: this.getDocumentListPreset(config, 'shared'),
recent: this.getDocumentListPreset(config, 'recent'), recent: this.getDocumentListPreset(config, 'recent'),
favorites: this.getDocumentListPreset(config, 'favorites'), favorites: this.getDocumentListPreset(config, 'favorites'),
trashcan: this.getDocumentListPreset(config, 'trashcan') trashcan: this.getDocumentListPreset(config, 'trashcan'),
searchLibraries: this.getDocumentListPreset(config, 'search-libraries')
}; };
} }

View File

@@ -1189,6 +1189,51 @@
"sortable": true, "sortable": true,
"desktopOnly": true "desktopOnly": true
} }
],
"search-libraries": [
{
"id": "app.libraries.thumbnail",
"key": "$thumbnail",
"type": "image",
"class": "image-table-cell",
"sortable": false,
"desktopOnly": false
},
{
"id": "app.libraries.name",
"key": "name",
"title": "APP.DOCUMENT_LIST.COLUMNS.NAME",
"type": "text",
"class": "adf-data-table-cell--ellipsis__name",
"sortable": true,
"template": "app.columns.libraryName",
"desktopOnly": false
},
{
"id": "app.libraries.id",
"key": "id",
"title": "APP.DOCUMENT_LIST.COLUMNS.ID",
"type": "text",
"sortable": true,
"desktopOnly": true
},
{
"id": "app.libraries.visibility",
"key": "visibility",
"title": "APP.DOCUMENT_LIST.COLUMNS.VISIBILITY",
"type": "text",
"sortable": true,
"template": "app.columns.libraryStatus",
"desktopOnly": true
},
{
"id": "app.libraries.role",
"key": "role",
"title": "APP.DOCUMENT_LIST.COLUMNS.ROLE",
"type": "text",
"sortable": true,
"desktopOnly": true
}
] ]
} }
} }

View File

@@ -111,6 +111,10 @@
"SIZE": "Size" "SIZE": "Size"
}, },
"NO_RESULTS": "Your search returned 0 results" "NO_RESULTS": "Your search returned 0 results"
},
"SEARCH_LIBRARIES": {
"TITLE": "Libraries found...",
"FOUND_RESULTS": "{{ number }} results"
} }
}, },
"ACTIONS": { "ACTIONS": {
@@ -145,6 +149,8 @@
}, },
"DOCUMENT_LIST": { "DOCUMENT_LIST": {
"COLUMNS": { "COLUMNS": {
"ID": "ID",
"ROLE": "Role",
"NAME": "Name", "NAME": "Name",
"SIZE": "Size", "SIZE": "Size",
"MODIFIED_ON": "Modified", "MODIFIED_ON": "Modified",