mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2025-05-12 17:04:46 +00:00
[ACS-6813] ACA configurable layout for search result list (#3656)
* [ACS-6813] Make search results list column configurable * [ACS-6813] Documentation update * [ACS-6813] Typo fix
This commit is contained in:
parent
1141b810cb
commit
930e4b1f3c
@ -44,6 +44,33 @@ All the customizations are stored in the `features` section of the configuration
|
|||||||
Other applications or external plugins can utilise different subsets of the configuration above.
|
Other applications or external plugins can utilise different subsets of the configuration above.
|
||||||
Also, extra entries can be added to the configuration schema.
|
Also, extra entries can be added to the configuration schema.
|
||||||
|
|
||||||
|
## Customizing list columns
|
||||||
|
|
||||||
|
To modify default columns layout for lists in personal files, libraries, favorite libraries, shared, recent files, favorites and search results you can update the `app.extensions.json` file by modifying/inserting new entry to the corresponding section of `features.documentList`. For example modifying `search-results` section:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"documentList": {
|
||||||
|
"search-results": [
|
||||||
|
{
|
||||||
|
"id": "app.search.type",
|
||||||
|
"key": "nodeType",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.TYPE",
|
||||||
|
"type": "text",
|
||||||
|
"class": "adf-ellipsis-cell",
|
||||||
|
"sortable": true,
|
||||||
|
"desktopOnly": false,
|
||||||
|
"order": 102
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
will result in new column being displayed in search results list. Any number of columns can be added, modified or removed from any section.
|
||||||
|
|
||||||
## Content Actions
|
## Content Actions
|
||||||
|
|
||||||
Most of the UI elements that operate with content, like toolbar buttons or menus,
|
Most of the UI elements that operate with content, like toolbar buttons or menus,
|
||||||
|
@ -924,6 +924,12 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "$ref": "#/definitions/documentListPresetRef" },
|
"items": { "$ref": "#/definitions/documentListPresetRef" },
|
||||||
"minItems": 1
|
"minItems": 1
|
||||||
|
},
|
||||||
|
"search-results": {
|
||||||
|
"description": "Search results list preset",
|
||||||
|
"type": "array",
|
||||||
|
"items": { "$ref": "#/definitions/documentListPresetRef" },
|
||||||
|
"minItems": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2754,6 +2754,69 @@
|
|||||||
"order": 50,
|
"order": 50,
|
||||||
"draggable": true
|
"draggable": true
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"search-results": [
|
||||||
|
{
|
||||||
|
"id": "app.search.name",
|
||||||
|
"key": "name",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.NAME",
|
||||||
|
"type": "text",
|
||||||
|
"class": "adf-ellipsis-cell adf-expand-cell-5",
|
||||||
|
"sortable": false,
|
||||||
|
"template": "app.search.columns.name",
|
||||||
|
"desktopOnly": false,
|
||||||
|
"order": 20,
|
||||||
|
"draggable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.search.size",
|
||||||
|
"key": "content.sizeInBytes",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.SIZE",
|
||||||
|
"type": "fileSize",
|
||||||
|
"class": "adf-no-grow-cell adf-ellipsis-cell",
|
||||||
|
"sortable": false,
|
||||||
|
"desktopOnly": true,
|
||||||
|
"order": 30,
|
||||||
|
"draggable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.search.modifiedOn",
|
||||||
|
"key": "modifiedAt",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON",
|
||||||
|
"type": "date",
|
||||||
|
"format": "timeAgo",
|
||||||
|
"class": "adf-ellipsis-cell adf-no-grow-cell",
|
||||||
|
"sortable": false,
|
||||||
|
"desktopOnly": true,
|
||||||
|
"order": 40,
|
||||||
|
"draggable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.search.modifiedBy",
|
||||||
|
"key": "modifiedByUser.displayName",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY",
|
||||||
|
"type": "text",
|
||||||
|
"class": "adf-ellipsis-cell adf-expand-cell-2 adf-min-width-cell",
|
||||||
|
"sortable": false,
|
||||||
|
"desktopOnly": true,
|
||||||
|
"order": 50,
|
||||||
|
"draggable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "app.search.tags",
|
||||||
|
"template": "app.columns.tags",
|
||||||
|
"key": "tags",
|
||||||
|
"title": "APP.DOCUMENT_LIST.COLUMNS.TAGS",
|
||||||
|
"class": "adf-full-width adf-expand-cell-4",
|
||||||
|
"type": "text",
|
||||||
|
"sortable": false,
|
||||||
|
"desktopOnly": true,
|
||||||
|
"order": 60,
|
||||||
|
"draggable": true,
|
||||||
|
"rules": {
|
||||||
|
"visible": "app.areTagsEnabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ import { ViewProfileComponent } from './components/view-profile/view-profile.com
|
|||||||
import { TrashcanComponent } from './components/trashcan/trashcan.component';
|
import { TrashcanComponent } from './components/trashcan/trashcan.component';
|
||||||
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
import { SharedLinkViewComponent } from './components/shared-link-view/shared-link-view.component';
|
||||||
import { MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
|
import { MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material/dialog';
|
||||||
|
import { SearchResultsRowComponent } from './components/search/search-results-row/search-results-row.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@ -174,7 +175,8 @@ export class ContentServiceExtensionModule {
|
|||||||
'app.logout': LogoutComponent,
|
'app.logout': LogoutComponent,
|
||||||
'app.user': UserInfoComponent,
|
'app.user': UserInfoComponent,
|
||||||
'app.notification-center': NotificationHistoryComponent,
|
'app.notification-center': NotificationHistoryComponent,
|
||||||
'app.user.menu': UserMenuComponent
|
'app.user.menu': UserMenuComponent,
|
||||||
|
'app.search.columns.name': SearchResultsRowComponent
|
||||||
});
|
});
|
||||||
|
|
||||||
extensions.setEvaluators({
|
extensions.setEvaluators({
|
||||||
|
@ -58,20 +58,44 @@
|
|||||||
</adf-data-column-header>
|
</adf-data-column-header>
|
||||||
</data-column>
|
</data-column>
|
||||||
|
|
||||||
<data-column id="app.search.name" key type="text" class="adf-ellipsis-cell adf-expand-cell-5" title="APP.DOCUMENT_LIST.COLUMNS.NAME" [sortable]="false" [draggable]="true">
|
<ng-container *ngFor="let column of columns; trackBy: trackByColumnId">
|
||||||
<ng-template let-context>
|
<ng-container *ngIf="column.template && !(column.desktopOnly && isSmallScreen)">
|
||||||
<aca-search-results-row [context]="context"></aca-search-results-row>
|
<data-column
|
||||||
</ng-template>
|
[id]="column.id"
|
||||||
</data-column>
|
[key]="column.key"
|
||||||
|
[title]="column.title"
|
||||||
|
[type]="column.type"
|
||||||
|
[format]="column.format"
|
||||||
|
[class]="column.class"
|
||||||
|
[sortable]="column.sortable"
|
||||||
|
[sortingKey]="column.sortingKey || column.key"
|
||||||
|
[isHidden]="column.isHidden"
|
||||||
|
[draggable]="column.draggable"
|
||||||
|
[resizable]="column.resizable"
|
||||||
|
>
|
||||||
|
<ng-template let-context>
|
||||||
|
<adf-dynamic-column [id]="column.template" [context]="context"> </adf-dynamic-column>
|
||||||
|
</ng-template>
|
||||||
|
</data-column>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<data-column id="app.search.size" key="content.sizeInBytes" type="fileSize" title="APP.DOCUMENT_LIST.COLUMNS.SIZE" class="adf-no-grow-cell adf-ellipsis-cell" [sortable]="false" *ngIf="!isSmallScreen" [draggable]="true"></data-column>
|
<ng-container *ngIf="!column.template && !(column.desktopOnly && isSmallScreen)">
|
||||||
<data-column id="app.search.modifiedOn" key="modifiedAt" type="date" title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON" class="adf-no-grow-cell adf-ellipsis-cell" format="timeAgo" [sortable]="false" *ngIf="!isSmallScreen" [draggable]="true"></data-column>
|
<data-column
|
||||||
<data-column id="app.search.modifiedBy" key="modifiedByUser.displayName" title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY" class="adf-no-grow-cell adf-ellipsis-cell" [sortable]="false" *ngIf="!isSmallScreen" [draggable]="true"></data-column>
|
[id]="column.id"
|
||||||
<data-column id="app.search.tags" key="$tags" type="text" title="APP.DOCUMENT_LIST.COLUMNS.TAGS" class="adf-full-width adf-expand-cell-4" [sortable]="false" [draggable]="true" *ngIf="isTagsEnabled">
|
[key]="column.key"
|
||||||
<ng-template let-context>
|
[title]="column.title"
|
||||||
<aca-tags-column [context]="context"></aca-tags-column>
|
[type]="column.type"
|
||||||
</ng-template>
|
[format]="column.format"
|
||||||
</data-column>
|
[class]="column.class"
|
||||||
|
[sortable]="column.sortable"
|
||||||
|
[sortingKey]="column.sortingKey || column.key"
|
||||||
|
[isHidden]="column.isHidden"
|
||||||
|
[draggable]="column.draggable"
|
||||||
|
[resizable]="column.resizable"
|
||||||
|
>
|
||||||
|
</data-column>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
</data-columns>
|
</data-columns>
|
||||||
|
|
||||||
<adf-custom-empty-content-template>
|
<adf-custom-empty-content-template>
|
||||||
|
@ -22,15 +22,15 @@
|
|||||||
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
* from Hyland Software. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing';
|
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||||
import { SearchResultsComponent } from './search-results.component';
|
import { SearchResultsComponent } from './search-results.component';
|
||||||
import { AppConfigService, TranslationService } from '@alfresco/adf-core';
|
import { AppConfigService, TranslationService } from '@alfresco/adf-core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { NavigateToFolder, SnackbarErrorAction } from '@alfresco/aca-shared/store';
|
import { NavigateToFolder, SnackbarErrorAction } from '@alfresco/aca-shared/store';
|
||||||
import { Pagination, ResultSetPaging, SearchRequest } from '@alfresco/js-api';
|
import { Pagination, SearchRequest } from '@alfresco/js-api';
|
||||||
import { SearchQueryBuilderService, TagService } from '@alfresco/adf-content-services';
|
import { SearchQueryBuilderService } from '@alfresco/adf-content-services';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { BehaviorSubject, of, Subject } from 'rxjs';
|
import { BehaviorSubject, Subject } from 'rxjs';
|
||||||
import { AppTestingModule } from '../../../testing/app-testing.module';
|
import { AppTestingModule } from '../../../testing/app-testing.module';
|
||||||
import { AppService } from '@alfresco/aca-shared';
|
import { AppService } from '@alfresco/aca-shared';
|
||||||
|
|
||||||
@ -274,80 +274,4 @@ describe('SearchComponent', () => {
|
|||||||
expect(queryBuilder.userQuery).toBe(`((=cm:tag:"orange"))`);
|
expect(queryBuilder.userQuery).toBe(`((=cm:tag:"orange"))`);
|
||||||
expect(queryBuilder.update).toHaveBeenCalled();
|
expect(queryBuilder.update).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Dynamic Columns', () => {
|
|
||||||
let tagsService: TagService;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
tagsService = TestBed.inject(TagService);
|
|
||||||
|
|
||||||
spyOn(queryBuilder['searchApi'], 'search').and.returnValue(
|
|
||||||
Promise.resolve({
|
|
||||||
list: {
|
|
||||||
pagination: {
|
|
||||||
count: 1,
|
|
||||||
hasMoreItems: false,
|
|
||||||
totalItems: 1,
|
|
||||||
skipCount: 0,
|
|
||||||
maxItems: 25
|
|
||||||
},
|
|
||||||
entries: [
|
|
||||||
{
|
|
||||||
entry: {
|
|
||||||
isFile: true,
|
|
||||||
nodeType: 'cm:content',
|
|
||||||
isFolder: false,
|
|
||||||
name: 'test-file.txt',
|
|
||||||
id: '8dd4d319-ec9f-4ea0-8276-f3b195918477'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
} as ResultSetPaging)
|
|
||||||
);
|
|
||||||
|
|
||||||
spyOn(queryBuilder, 'buildQuery').and.returnValue(searchRequest);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not show tags column if tags are disabled', fakeAsync(() => {
|
|
||||||
spyOn(tagsService, 'areTagsEnabled').and.returnValue(false);
|
|
||||||
fixture = TestBed.createComponent(SearchResultsComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
queryBuilder.execute();
|
|
||||||
tick();
|
|
||||||
fixture.detectChanges();
|
|
||||||
const tagsColumnHeader = fixture.nativeElement.querySelector(`[data-automation-id='auto_id_$tags']`);
|
|
||||||
expect(tagsColumnHeader).toBeNull();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should show tags column if tags are enabled', fakeAsync(() => {
|
|
||||||
spyOn(tagsService, 'areTagsEnabled').and.returnValue(true);
|
|
||||||
spyOn(tagsService, 'getTagsByNodeId').and.returnValue(
|
|
||||||
of({
|
|
||||||
list: {
|
|
||||||
pagination: {
|
|
||||||
count: 0,
|
|
||||||
hasMoreItems: false,
|
|
||||||
totalItems: 0,
|
|
||||||
skipCount: 0,
|
|
||||||
maxItems: 100
|
|
||||||
},
|
|
||||||
entries: []
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
fixture = TestBed.createComponent(SearchResultsComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
queryBuilder.execute();
|
|
||||||
tick();
|
|
||||||
fixture.detectChanges();
|
|
||||||
const tagsColumnHeader = fixture.nativeElement.querySelector(`[data-automation-id='auto_id_$tags']`);
|
|
||||||
expect(tagsColumnHeader).not.toBeNull();
|
|
||||||
flush();
|
|
||||||
}));
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
fixture.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
@ -59,6 +59,7 @@ import { SearchActionMenuComponent } from '../search-action-menu/search-action-m
|
|||||||
import { TagsColumnComponent } from '../../dl-custom-components/tags-column/tags-column.component';
|
import { TagsColumnComponent } from '../../dl-custom-components/tags-column/tags-column.component';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { SearchResultsRowComponent } from '../search-results-row/search-results-row.component';
|
import { SearchResultsRowComponent } from '../search-results-row/search-results-row.component';
|
||||||
|
import { DocumentListPresetRef, ExtensionsModule } from '@alfresco/adf-extensions';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
@ -85,7 +86,8 @@ import { SearchResultsRowComponent } from '../search-results-row/search-results-
|
|||||||
PaginationDirective,
|
PaginationDirective,
|
||||||
ViewerModule,
|
ViewerModule,
|
||||||
PageLayoutComponent,
|
PageLayoutComponent,
|
||||||
ToolbarComponent
|
ToolbarComponent,
|
||||||
|
ExtensionsModule
|
||||||
],
|
],
|
||||||
selector: 'aca-search-results',
|
selector: 'aca-search-results',
|
||||||
templateUrl: './search-results.component.html',
|
templateUrl: './search-results.component.html',
|
||||||
@ -103,6 +105,7 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
isLoading = false;
|
isLoading = false;
|
||||||
totalResults: number;
|
totalResults: number;
|
||||||
isTagsEnabled = false;
|
isTagsEnabled = false;
|
||||||
|
columns: DocumentListPresetRef[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
tagsService: TagService,
|
tagsService: TagService,
|
||||||
@ -157,6 +160,8 @@ export class SearchResultsComponent extends PageComponent implements OnInit {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.columns = this.extensions.documentListPresets.searchResults || [];
|
||||||
|
|
||||||
if (this.route) {
|
if (this.route) {
|
||||||
this.route.params.forEach((params: Params) => {
|
this.route.params.forEach((params: Params) => {
|
||||||
// eslint-disable-next-line no-prototype-builtins
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
@ -92,6 +92,7 @@ export class AppExtensionService implements RuleContext {
|
|||||||
favorites: Array<DocumentListPresetRef>;
|
favorites: Array<DocumentListPresetRef>;
|
||||||
trashcan: Array<DocumentListPresetRef>;
|
trashcan: Array<DocumentListPresetRef>;
|
||||||
searchLibraries: Array<DocumentListPresetRef>;
|
searchLibraries: Array<DocumentListPresetRef>;
|
||||||
|
searchResults: Array<DocumentListPresetRef>;
|
||||||
} = {
|
} = {
|
||||||
libraries: [],
|
libraries: [],
|
||||||
favoriteLibraries: [],
|
favoriteLibraries: [],
|
||||||
@ -99,7 +100,8 @@ export class AppExtensionService implements RuleContext {
|
|||||||
recent: [],
|
recent: [],
|
||||||
favorites: [],
|
favorites: [],
|
||||||
trashcan: [],
|
trashcan: [],
|
||||||
searchLibraries: []
|
searchLibraries: [],
|
||||||
|
searchResults: []
|
||||||
};
|
};
|
||||||
|
|
||||||
selection: SelectionState;
|
selection: SelectionState;
|
||||||
@ -179,7 +181,8 @@ export class AppExtensionService implements RuleContext {
|
|||||||
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')
|
searchLibraries: this.getDocumentListPreset(config, 'search-libraries'),
|
||||||
|
searchResults: this.getDocumentListPreset(config, 'search-results')
|
||||||
};
|
};
|
||||||
|
|
||||||
this.withCredentials = this.appConfig.get<boolean>('auth.withCredentials', false);
|
this.withCredentials = this.appConfig.get<boolean>('auth.withCredentials', false);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user