mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-551] sorting for document list (#1891)
* table cell component - table cell component with performance improvements * permissions and sorting fixes - fixed ability to set default sorting - fixed permission evaluation - new: context menu now also works with permissions - disabled tags column in demo shell due to performance implications * fix unit tests * fix tsconfig for unit testing
This commit is contained in:
committed by
Eugenio Romano
parent
ef5bb6333c
commit
da18a21e7c
@@ -45,6 +45,8 @@
|
||||
-->
|
||||
|
||||
</data-column>
|
||||
<!-- Notes: has performance problems due to multiple files/folders causing separate HTTP calls to get tags -->
|
||||
<!--
|
||||
<data-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.TAG' | translate}}"
|
||||
key="id"
|
||||
@@ -53,6 +55,7 @@
|
||||
<alfresco-tag-node-list [nodeId]="entry.data.getValue(entry.row, entry.col)"></alfresco-tag-node-list>
|
||||
</template>
|
||||
</data-column>
|
||||
-->
|
||||
<data-column
|
||||
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
|
||||
key="createdByUser.displayName"
|
||||
|
@@ -21,9 +21,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -52,7 +52,10 @@ import { ContextMenuService } from './context-menu.service';
|
||||
template: `
|
||||
<div [ngStyle]="locationCss" class="menu-container">
|
||||
<ul class="context-menu">
|
||||
<li (click)="link.subject.next(link)" class="mdl-menu__item link" *ngFor="let link of links">
|
||||
<li *ngFor="let link of links"
|
||||
class="mdl-menu__item link"
|
||||
(click)="onMenuItemClick($event, link)"
|
||||
[attr.disabled]="link.model?.disabled || undefined">
|
||||
{{link.title || link.model?.title}}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -82,6 +85,15 @@ export class ContextMenuHolderComponent {
|
||||
this.isShown = false;
|
||||
}
|
||||
|
||||
onMenuItemClick(event: Event, menuItem: any): void {
|
||||
if (menuItem && menuItem.model && menuItem.model.disabled) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
return;
|
||||
}
|
||||
menuItem.subject.next(menuItem);
|
||||
}
|
||||
|
||||
showMenu(e, links) {
|
||||
this.isShown = true;
|
||||
this.links = links;
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -27,9 +27,11 @@ export * from './src/components/datatable/data-row-action.event';
|
||||
import { DataTableComponent } from './src/components/datatable/datatable.component';
|
||||
import { NoContentTemplateComponent } from './src/components/datatable/no-content-template.component';
|
||||
import { PaginationComponent } from './src/components/pagination/pagination.component';
|
||||
import { DataTableCellComponent } from './src/components/datatable/datatable-cell.component';
|
||||
|
||||
export const ALFRESCO_DATATABLE_DIRECTIVES: [any] = [
|
||||
DataTableComponent,
|
||||
DataTableCellComponent,
|
||||
NoContentTemplateComponent,
|
||||
PaginationComponent
|
||||
];
|
||||
|
@@ -0,0 +1,48 @@
|
||||
/*!
|
||||
* @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 { Component, Input, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { DataTableAdapter, DataColumn, DataRow } from '../../data/index';
|
||||
|
||||
@Component({
|
||||
selector: 'alfresco-datatable-cell',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
template: '<ng-container>{{value}}</ng-container>'
|
||||
})
|
||||
export class DataTableCellComponent {
|
||||
|
||||
@Input()
|
||||
data: DataTableAdapter;
|
||||
|
||||
@Input()
|
||||
column: DataColumn;
|
||||
|
||||
@Input()
|
||||
row: DataRow;
|
||||
|
||||
@Input()
|
||||
value: any;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
if (this.column && this.column.key && this.row && this.data) {
|
||||
this.value = this.data.getValue(this.row, this.column);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -70,10 +70,10 @@
|
||||
(error)="onImageLoadingError($event)">
|
||||
</div>
|
||||
<div *ngSwitchCase="'date'" class="cell-value" [attr.data-automation-id]="'date_' + data.getValue(row, col)">
|
||||
{{data.getValue(row, col)}}
|
||||
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
||||
</div>
|
||||
<div *ngSwitchCase="'text'" class="cell-value" [attr.data-automation-id]="'text_' + data.getValue(row, col)">
|
||||
{{data.getValue(row, col)}}
|
||||
<alfresco-datatable-cell [data]="data" [column]="col" [row]="row"></alfresco-datatable-cell>
|
||||
</div>
|
||||
<span *ngSwitchDefault class="cell-value">
|
||||
<!-- empty cell for unknown column type -->
|
||||
@@ -95,7 +95,7 @@
|
||||
</button>
|
||||
<ul alfresco-mdl-menu class="mdl-menu--bottom-right"
|
||||
[attr.for]="'action_menu_' + idx">
|
||||
<li class="mdl-menu__item" [attr.disabled]="action.disabled"
|
||||
<li class="mdl-menu__item" [attr.disabled]="action.disabled || undefined"
|
||||
[attr.data-automation-id]="action.title"
|
||||
*ngFor="let action of getRowActions(row)"
|
||||
(click)="onExecuteRowAction(row, action)">
|
||||
|
@@ -20,6 +20,7 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { MdCheckboxChange } from '@angular/material';
|
||||
import { DataTableComponent } from './datatable.component';
|
||||
import { DataTableCellComponent } from './datatable-cell.component';
|
||||
import {
|
||||
DataRow,
|
||||
DataColumn,
|
||||
@@ -40,7 +41,10 @@ describe('DataTable', () => {
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
declarations: [DataTableComponent]
|
||||
declarations: [
|
||||
DataTableCellComponent,
|
||||
DataTableComponent
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
|
@@ -258,7 +258,7 @@ export class DataTableComponent implements AfterContentInit, OnChanges {
|
||||
}
|
||||
|
||||
onExecuteRowAction(row: DataRow, action: any) {
|
||||
if (action.disabled) {
|
||||
if (action.disabled || action.disabled) {
|
||||
event.stopPropagation();
|
||||
} else {
|
||||
this.executeRowAction.emit(new DataRowActionEvent(row, action));
|
||||
|
@@ -17,3 +17,4 @@
|
||||
|
||||
export * from './datatable.component';
|
||||
export * from './no-content-template.component';
|
||||
export * from './datatable-cell.component';
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -47,6 +47,9 @@ export class ContentActionComponent implements OnInit, OnChanges {
|
||||
@Input()
|
||||
disableWithNoPermission: boolean;
|
||||
|
||||
@Input()
|
||||
disabled: boolean = false;
|
||||
|
||||
@Output()
|
||||
execute = new EventEmitter();
|
||||
|
||||
@@ -68,7 +71,8 @@ export class ContentActionComponent implements OnInit, OnChanges {
|
||||
icon: this.icon,
|
||||
permission: this.permission,
|
||||
disableWithNoPermission: this.disableWithNoPermission,
|
||||
target: this.target
|
||||
target: this.target,
|
||||
disabled: this.disabled
|
||||
});
|
||||
|
||||
if (this.handler) {
|
||||
|
@@ -30,6 +30,8 @@ describe('ContentColumnList', () => {
|
||||
let service = new DocumentListServiceMock();
|
||||
documentList = new DocumentListComponent(service, null, null, null);
|
||||
columnList = new ContentColumnListComponent(documentList);
|
||||
|
||||
documentList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should register column within parent document list', () => {
|
||||
|
@@ -29,6 +29,8 @@ describe('ContentColumn', () => {
|
||||
let service = new DocumentListServiceMock();
|
||||
documentList = new DocumentListComponent(service, null, null, null);
|
||||
columnList = new ContentColumnListComponent(documentList);
|
||||
|
||||
documentList.ngOnInit();
|
||||
});
|
||||
|
||||
it('should register model within parent column list', () => {
|
||||
|
@@ -157,11 +157,11 @@ describe('DocumentList', () => {
|
||||
|
||||
let actions = documentList.getNodeActions(new FolderNode());
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(folderMenu);
|
||||
expect(actions[0].target).toBe(folderMenu.target);
|
||||
|
||||
actions = documentList.getNodeActions(new FileNode());
|
||||
expect(actions.length).toBe(1);
|
||||
expect(actions[0]).toBe(documentMenu);
|
||||
expect(actions[0].target).toBe(documentMenu.target);
|
||||
});
|
||||
|
||||
it('should disable the action if there is no permission for the file and disableWithNoPermission true', () => {
|
||||
|
@@ -28,7 +28,8 @@ import {
|
||||
ObjectDataColumn,
|
||||
DataCellEvent,
|
||||
DataRowActionEvent,
|
||||
DataColumn
|
||||
DataColumn,
|
||||
DataSorting
|
||||
} from 'ng2-alfresco-datatable';
|
||||
import { DocumentListService } from './../services/document-list.service';
|
||||
import { ContentActionModel } from './../models/content-action.model';
|
||||
@@ -156,8 +157,6 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
private translateService: AlfrescoTranslationService,
|
||||
private el: ElementRef) {
|
||||
|
||||
this.data = new ShareDataTableAdapter(this.documentListService);
|
||||
|
||||
if (translateService) {
|
||||
translateService.addTranslationFolder('ng2-alfresco-documentlist', 'node_modules/ng2-alfresco-documentlist/src');
|
||||
}
|
||||
@@ -186,6 +185,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.data = new ShareDataTableAdapter(this.documentListService, null, this.getDefaultSorting());
|
||||
this.data.thumbnails = this.thumbnails;
|
||||
this.contextActionHandler.subscribe(val => this.contextActionCallback(val));
|
||||
|
||||
@@ -200,7 +200,7 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
}
|
||||
|
||||
if (!this.data) {
|
||||
this.data = new ShareDataTableAdapter(this.documentListService, schema);
|
||||
this.data = new ShareDataTableAdapter(this.documentListService, schema, this.getDefaultSorting());
|
||||
} else if (schema && schema.length > 0) {
|
||||
this.data.setColumns(schema);
|
||||
}
|
||||
@@ -209,18 +209,6 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
if (!columns || columns.length === 0) {
|
||||
this.setupDefaultColumns();
|
||||
}
|
||||
|
||||
// TODO: commented out as Permissions feature (Context Menus and Row Actions) breaks all component functionality
|
||||
/*
|
||||
if (this.sorting) {
|
||||
const [ key, direction ] = this.sorting;
|
||||
|
||||
this.data.setSorting({
|
||||
key,
|
||||
direction: direction || 'asc'
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
@@ -294,28 +282,21 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
|
||||
if (target) {
|
||||
let ltarget = target.toLowerCase();
|
||||
let actionWithPermission = this.checkPermissions(node);
|
||||
|
||||
let actionsByTarget = actionWithPermission.filter(entry => {
|
||||
let actionsByTarget = this.actions.filter(entry => {
|
||||
return entry.target.toLowerCase() === ltarget;
|
||||
}).map(action => new ContentActionModel(action));
|
||||
|
||||
actionsByTarget.forEach((action) => {
|
||||
this.checkPermission(node, action);
|
||||
});
|
||||
|
||||
let cloneActions = Object.create(actionsByTarget);
|
||||
return cloneActions;
|
||||
return actionsByTarget;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
checkPermissions(node: MinimalNodeEntity): ContentActionModel[] {
|
||||
let actionsPermission: ContentActionModel[] = [];
|
||||
this.actions.forEach((action) => {
|
||||
actionsPermission.push(this.checkPermission(node, action));
|
||||
});
|
||||
return actionsPermission;
|
||||
}
|
||||
|
||||
checkPermission(node: any, action: ContentActionModel): ContentActionModel {
|
||||
if (action.permission) {
|
||||
if (this.hasPermissions(node)) {
|
||||
@@ -562,4 +543,13 @@ export class DocumentListComponent implements OnInit, OnChanges, AfterContentIni
|
||||
this.navigationMode = DocumentListComponent.SINGLE_CLICK_NAVIGATION;
|
||||
}
|
||||
}
|
||||
|
||||
private getDefaultSorting(): DataSorting {
|
||||
let defaultSorting: DataSorting;
|
||||
if (this.sorting) {
|
||||
const [ key, direction ] = this.sorting;
|
||||
defaultSorting = new DataSorting(key, direction);
|
||||
}
|
||||
return defaultSorting;
|
||||
}
|
||||
}
|
||||
|
@@ -41,9 +41,11 @@ export class ShareDataTableAdapter implements DataTableAdapter {
|
||||
selectedRow: DataRow;
|
||||
|
||||
constructor(private documentListService: DocumentListService,
|
||||
schema: DataColumn[] = []) {
|
||||
schema: DataColumn[] = [],
|
||||
sorting?: DataSorting) {
|
||||
this.rows = [];
|
||||
this.columns = schema || [];
|
||||
this.sorting = sorting;
|
||||
}
|
||||
|
||||
getRows(): Array<DataRow> {
|
||||
|
@@ -21,8 +21,8 @@ export class ContentActionModel {
|
||||
handler: ContentActionHandler;
|
||||
target: string;
|
||||
permission: string;
|
||||
disableWithNoPermission: boolean;
|
||||
disabled: boolean;
|
||||
disableWithNoPermission: boolean = false;
|
||||
disabled: boolean = false;
|
||||
|
||||
constructor(obj?: any) {
|
||||
if (obj) {
|
||||
@@ -32,6 +32,7 @@ export class ContentActionModel {
|
||||
this.target = obj.target;
|
||||
this.permission = obj.permission;
|
||||
this.disableWithNoPermission = obj.disableWithNoPermission;
|
||||
this.disabled = obj.disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -41,9 +41,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
@@ -21,9 +21,6 @@
|
||||
"es2015",
|
||||
"dom"
|
||||
],
|
||||
"typeRoots": [
|
||||
"./node_modules/@types"
|
||||
],
|
||||
"suppressImplicitAnyIndexErrors": true
|
||||
},
|
||||
"exclude": [
|
||||
|
Reference in New Issue
Block a user