[ADF-3912] Improved folder retrieving for DL (#4423)

* [ADF-3912] added abstract class for document-list component to be provided

* [ADF-3912] - created abstract class for document-list service

* [ADF-3912] - fixing and removing the custom resource from document-list

* [ADF-3912] added interface for document list service

* [ADF-3912] added interface for loadFolderById for DL component

* [ADF-3912] fixed missing return type

* [ADF-3912] removed comment

* [ADF-3912] fixed PR comments

* [ADF-3912] fixed wrong import

* [ADF-3912] fixed unit test failing

* [ADF-3912] removed unused method

* [ADF-3912] fixed lint problems
This commit is contained in:
Vito 2019-03-27 13:10:59 +00:00 committed by Eugenio Romano
parent 3b1c4923b2
commit a2823eeb99
14 changed files with 256 additions and 166 deletions

View File

@ -20,25 +20,29 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PathElementEntity } from '@alfresco/js-api';
import { setupTestBed } from '@alfresco/adf-core';
import { fakeNodeWithCreatePermission } from '../mock';
import { DocumentListComponent } from '../document-list';
import { DocumentListComponent, DocumentListService } from '../document-list';
import { BreadcrumbComponent } from './breadcrumb.component';
import { ContentTestingModule } from '../testing/content.testing.module';
import { of } from 'rxjs';
describe('Breadcrumb', () => {
let component: BreadcrumbComponent;
let fixture: ComponentFixture<BreadcrumbComponent>;
let documentList: DocumentListComponent;
let documentListService: DocumentListService = jasmine.createSpyObj({'loadFolderByNodeId' : of(''), 'isCustomSourceService': false});
let documentListComponent: DocumentListComponent;
setupTestBed({
imports: [ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers : [{ provide: DocumentListService, useValue: documentListService }]
});
beforeEach(() => {
fixture = TestBed.createComponent(BreadcrumbComponent);
component = fixture.componentInstance;
documentList = TestBed.createComponent<DocumentListComponent>(DocumentListComponent).componentInstance;
documentListComponent = TestBed.createComponent<DocumentListComponent>(DocumentListComponent).componentInstance;
documentListService = TestBed.get(DocumentListService);
});
afterEach(() => {
@ -69,17 +73,17 @@ describe('Breadcrumb', () => {
component.onRoutePathClick(node, null);
});
it('should update document list on click', (done) => {
spyOn(documentList, 'loadFolderByNodeId').and.stub();
it('should update document list on click', () => {
const node = <PathElementEntity> { id: '-id-', name: 'name' };
component.target = documentList;
component.target = documentListComponent;
component.onRoutePathClick(node, null);
setTimeout(() => {
expect(documentList.loadFolderByNodeId).toHaveBeenCalledWith(node.id);
done();
}, 0);
expect(documentListService.loadFolderByNodeId).toHaveBeenCalledWith(node.id,
documentListComponent.DEFAULT_PAGINATION,
documentListComponent.includeFields,
documentListComponent.where);
});
it('should not parse the route when node not provided', () => {

View File

@ -20,25 +20,29 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { setupTestBed } from '@alfresco/adf-core';
import { fakeNodeWithCreatePermission } from '../mock';
import { DocumentListComponent } from '../document-list';
import { DocumentListComponent, DocumentListService } from '../document-list';
import { DropdownBreadcrumbComponent } from './dropdown-breadcrumb.component';
import { ContentTestingModule } from '../testing/content.testing.module';
import { of } from 'rxjs';
describe('DropdownBreadcrumb', () => {
let component: DropdownBreadcrumbComponent;
let fixture: ComponentFixture<DropdownBreadcrumbComponent>;
let documentList: DocumentListComponent;
let documentListService: DocumentListService = jasmine.createSpyObj({'loadFolderByNodeId' : of(''), 'isCustomSourceService': false});
setupTestBed({
imports: [ContentTestingModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers : [{ provide: DocumentListService, useValue: documentListService }]
});
beforeEach(async(() => {
fixture = TestBed.createComponent(DropdownBreadcrumbComponent);
component = fixture.componentInstance;
documentList = TestBed.createComponent<DocumentListComponent>(DocumentListComponent).componentInstance;
documentListService = TestBed.get(DocumentListService);
}));
afterEach(async(() => {
@ -151,7 +155,6 @@ describe('DropdownBreadcrumb', () => {
});
it('should update document list when clicking on an option', (done) => {
spyOn(documentList, 'loadFolderByNodeId').and.stub();
component.target = documentList;
const fakeNodeWithCreatePermissionInstance = JSON.parse(JSON.stringify(fakeNodeWithCreatePermission));
fakeNodeWithCreatePermissionInstance.path.elements = [{ id: '1', name: 'Stark Industries' }];
@ -160,10 +163,9 @@ describe('DropdownBreadcrumb', () => {
fixture.whenStable().then(() => {
openSelect();
fixture.whenStable().then(() => {
clickOnTheFirstOption();
expect(documentList.loadFolderByNodeId).toHaveBeenCalledWith('1');
expect(documentListService.loadFolderByNodeId).toHaveBeenCalledWith('1', documentList.DEFAULT_PAGINATION, undefined, undefined);
done();
});
});

View File

@ -17,7 +17,7 @@
import { MatDialog } from '@angular/material';
import { EventEmitter, Injectable, Output } from '@angular/core';
import { ContentService } from '@alfresco/adf-core';
import { ContentService, ThumbnailService } from '@alfresco/adf-core';
import { Subject, Observable, throwError } from 'rxjs';
import { ShareDataRow } from '../document-list/data/share-data-row.model';
import { Node, NodeEntry, SitePaging } from '@alfresco/js-api';
@ -49,7 +49,8 @@ export class ContentNodeDialogService {
private contentService: ContentService,
private documentListService: DocumentListService,
private siteService: SitesService,
private translation: TranslationService) {
private translation: TranslationService,
private thumbnailService: ThumbnailService) {
}
/**
@ -224,7 +225,7 @@ export class ContentNodeDialogService {
private imageResolver(row: ShareDataRow, col: DataColumn): string | null {
const entry: Node = row.node.entry;
if (!this.contentService.hasAllowableOperations(entry, 'create')) {
return this.documentListService.getMimeTypeIcon('disable/folder');
return this.thumbnailService.getMimeTypeIcon('disable/folder');
}
return null;

View File

@ -866,9 +866,9 @@ describe('DocumentList', () => {
it('should display folder content from loadFolderByNodeId on reload if currentFolderId defined', () => {
documentList.currentFolderId = 'id-folder';
spyOn(documentList, 'loadFolderByNodeId').and.stub();
spyOn(documentList, 'loadFolder').and.stub();
documentList.reload();
expect(documentList.loadFolderByNodeId).toHaveBeenCalled();
expect(documentList.loadFolder).toHaveBeenCalled();
});
it('should require node to resolve context menu actions', () => {
@ -1050,8 +1050,8 @@ describe('DocumentList', () => {
disposableError.unsubscribe();
done();
});
documentList.loadFolderByNodeId('123');
documentList.currentFolderId = '123';
documentList.loadFolder();
});
it('should emit folderChange event when a folder node is clicked', (done) => {
@ -1075,7 +1075,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('123');
documentList.currentFolderId = '123';
documentList.loadFolder();
});
it('should reset noPermission upon reload', () => {
@ -1135,7 +1136,8 @@ describe('DocumentList', () => {
it('should fetch trashcan', () => {
spyOn(apiService.nodesApi, 'getDeletedNodes').and.returnValue(Promise.resolve(null));
documentList.loadFolderByNodeId('-trashcan-');
documentList.currentFolderId = '-trashcan-';
documentList.loadFolder();
expect(apiService.nodesApi.getDeletedNodes).toHaveBeenCalled();
});
@ -1148,14 +1150,16 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-trashcan-');
documentList.currentFolderId = '-trashcan-';
documentList.loadFolder();
});
it('should fetch shared links', () => {
const sharedlinksApi = apiService.getInstance().core.sharedlinksApi;
spyOn(sharedlinksApi, 'findSharedLinks').and.returnValue(Promise.resolve(null));
documentList.loadFolderByNodeId('-sharedlinks-');
documentList.currentFolderId = '-sharedlinks-';
documentList.loadFolder();
expect(sharedlinksApi.findSharedLinks).toHaveBeenCalled();
});
@ -1169,13 +1173,15 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-sharedlinks-');
documentList.currentFolderId = '-sharedlinks-';
documentList.loadFolder();
});
it('should fetch sites', () => {
const sitesApi = apiService.getInstance().core.sitesApi;
documentList.loadFolderByNodeId('-sites-');
documentList.currentFolderId = '-sites-';
documentList.loadFolder();
expect(sitesApi.getSites).toHaveBeenCalled();
});
@ -1188,7 +1194,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-sites-');
documentList.currentFolderId = '-sites-';
documentList.loadFolder();
});
it('should assure that sites have name property set', (done) => {
@ -1201,7 +1208,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-sites-');
documentList.currentFolderId = '-sites-';
documentList.loadFolder();
});
it('should assure that sites have name property set correctly', (done) => {
@ -1214,14 +1222,16 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-sites-');
documentList.currentFolderId = '-sites-';
documentList.loadFolder();
});
it('should fetch user membership sites', () => {
const peopleApi = apiService.getInstance().core.peopleApi;
spyOn(peopleApi, 'listSiteMembershipsForPerson').and.returnValue(Promise.resolve(fakeGetSiteMembership));
documentList.loadFolderByNodeId('-mysites-');
documentList.currentFolderId = '-mysites-';
documentList.loadFolder();
expect(peopleApi.listSiteMembershipsForPerson).toHaveBeenCalled();
});
@ -1235,7 +1245,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-mysites-');
documentList.currentFolderId = '-mysites-';
documentList.loadFolder();
});
it('should assure that user membership sites have name property set', (done) => {
@ -1243,7 +1254,8 @@ describe('DocumentList', () => {
const peopleApi = apiService.getInstance().core.peopleApi;
spyOn(peopleApi, 'listSiteMembershipsForPerson').and.returnValue(Promise.resolve(fakeGetSiteMembership));
documentList.loadFolderByNodeId('-mysites-');
documentList.currentFolderId = '-mysites-';
documentList.loadFolder();
expect(peopleApi.listSiteMembershipsForPerson).toHaveBeenCalled();
const disposableReady = documentList.ready.subscribe((page) => {
@ -1259,7 +1271,8 @@ describe('DocumentList', () => {
const peopleApi = apiService.getInstance().core.peopleApi;
spyOn(peopleApi, 'listSiteMembershipsForPerson').and.returnValue(Promise.resolve(fakeGetSiteMembership));
documentList.loadFolderByNodeId('-mysites-');
documentList.currentFolderId = '-mysites-';
documentList.loadFolder();
expect(peopleApi.listSiteMembershipsForPerson).toHaveBeenCalled();
const disposableReady = documentList.ready.subscribe((page) => {
@ -1274,7 +1287,8 @@ describe('DocumentList', () => {
const favoritesApi = apiService.getInstance().core.favoritesApi;
spyFavorite.and.returnValue(Promise.resolve(null));
documentList.loadFolderByNodeId('-favorites-');
documentList.currentFolderId = '-favorites-';
documentList.loadFolder();
expect(favoritesApi.getFavorites).toHaveBeenCalled();
});
@ -1287,7 +1301,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-favorites-');
documentList.currentFolderId = '-favorites-';
documentList.loadFolder();
});
it('should fetch recent', () => {
@ -1295,7 +1310,8 @@ describe('DocumentList', () => {
const getPersonSpy = spyOn(apiService.peopleApi, 'getPerson').and.returnValue(Promise.resolve(person));
documentList.loadFolderByNodeId('-recent-');
documentList.currentFolderId = '-recent-';
documentList.loadFolder();
expect(getPersonSpy).toHaveBeenCalledWith('-me-');
});
@ -1309,7 +1325,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-recent-');
documentList.currentFolderId = '-recent-';
documentList.loadFolder();
});
it('should emit error when fetch recent fails on search call', (done) => {
@ -1321,7 +1338,8 @@ describe('DocumentList', () => {
done();
});
documentList.loadFolderByNodeId('-recent-');
documentList.currentFolderId = '-recent-';
documentList.loadFolder();
});
it('should have correct currentFolderId on loading folder by node id', () => {
@ -1330,7 +1348,8 @@ describe('DocumentList', () => {
const peopleApi = apiService.getInstance().core.peopleApi;
spyOn(peopleApi, 'listSiteMembershipsForPerson').and.returnValue(Promise.resolve(fakeGetSiteMembership));
documentList.loadFolderByNodeId('-mysites-');
documentList.currentFolderId = '-mysites-';
documentList.loadFolder();
expect(documentList.currentFolderId).toBe('-mysites-');
});

View File

@ -53,12 +53,11 @@ import { ShareDataTableAdapter } from './../data/share-datatable-adapter';
import { presetsDefaultModel } from '../models/preset.model';
import { ContentActionModel } from './../models/content-action.model';
import { PermissionStyleModel } from './../models/permissions-style.model';
import { DocumentListService } from './../services/document-list.service';
import { NodeEntityEvent, NodeEntryEvent } from './node.event';
import { CustomResourcesService } from './../services/custom-resources.service';
import { NavigableComponentInterface } from '../../breadcrumb/navigable-component.interface';
import { RowFilter } from '../data/row-filter.model';
import { Observable } from 'rxjs/index';
import { DocumentListService } from '../services/document-list.service';
import { DocumentLoaderNode } from '../models/document-folder.model';
@Component({
selector: 'adf-document-list',
@ -323,7 +322,6 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
private elementRef: ElementRef,
private appConfig: AppConfigService,
private userPreferencesService: UserPreferencesService,
private customResourcesService: CustomResourcesService,
private contentService: ContentService,
private thumbnailService: ThumbnailService,
private alfrescoApiService: AlfrescoApiService,
@ -378,7 +376,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
ngOnInit() {
this.rowMenuCache = {};
this.loadLayoutPresets();
this.data = new ShareDataTableAdapter(this.documentListService, this.thumbnailService, this.contentService, null, this.getDefaultSorting(), this.sortingMode);
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, null, this.getDefaultSorting(), this.sortingMode);
this.data.thumbnails = this.thumbnails;
this.data.permissionsStyle = this.permissionsStyle;
@ -416,7 +414,7 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
}
if (!this.data) {
this.data = new ShareDataTableAdapter(this.documentListService, this.thumbnailService, this.contentService, schema, this.getDefaultSorting(), this.sortingMode);
this.data = new ShareDataTableAdapter(this.thumbnailService, this.contentService, schema, this.getDefaultSorting(), this.sortingMode);
} else if (schema && schema.length > 0) {
this.data.setColumns(schema);
}
@ -627,46 +625,21 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte
this.setupDefaultColumns(this._currentFolderId);
}
this.loadFolderByNodeId(this._currentFolderId);
if (this.documentListService.isCustomSourceService(this._currentFolderId)) {
this.updateCustomSourceData(this._currentFolderId);
}
loadFolderByNodeId(nodeId: string) {
if (this.customResourcesService.isCustomSource(nodeId)) {
this.updateCustomSourceData(nodeId);
this.customResourcesService.loadFolderByNodeId(nodeId, this._pagination, this.includeFields)
.subscribe((nodePaging: NodePaging) => {
this.onPageLoaded(nodePaging);
}, (err) => {
this.error.emit(err);
});
} else {
this.documentListService.getFolder(null, {
maxItems: this._pagination.maxItems,
skipCount: this._pagination.skipCount,
rootFolderId: nodeId,
where: this.where
}, this.includeFields)
.subscribe((nodePaging: NodePaging) => {
this.getSourceNodeWithPath(nodeId).subscribe((nodeEntry: NodeEntry) => {
this.onPageLoaded(nodePaging);
});
this.documentListService.loadFolderByNodeId(this._currentFolderId, this._pagination, this.includeFields, this.where)
.subscribe((documentNode: DocumentLoaderNode) => {
if (documentNode.currentNode) {
this.folderNode = documentNode.currentNode.entry;
this.$folderNode.next(documentNode.currentNode.entry);
}
this.onPageLoaded(documentNode.children);
}, (err) => {
this.handleError(err);
});
}
}
getSourceNodeWithPath(nodeId: string): Observable<NodeEntry> {
const getSourceObservable = this.documentListService.getFolderNode(nodeId, this.includeFields);
getSourceObservable.subscribe((nodeEntry: NodeEntry) => {
this.folderNode = nodeEntry.entry;
this.$folderNode.next(this.folderNode);
});
return getSourceObservable;
}
resetSelection() {
this.dataTable.resetSelection();

View File

@ -15,31 +15,64 @@
* limitations under the License.
*/
import { DataColumn, DataRow, DataSorting, ContentService } from '@alfresco/adf-core';
import { DataColumn, DataRow, DataSorting, ContentService, ThumbnailService } from '@alfresco/adf-core';
import { FileNode, FolderNode, SmartFolderNode, RuleFolderNode, LinkFolderNode } from './../../mock';
import { DocumentListService } from './../services/document-list.service';
import { ShareDataRow } from './share-data-row.model';
import { ShareDataTableAdapter } from './share-datatable-adapter';
import { DomSanitizer } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material';
class FakeSanitizer extends DomSanitizer {
constructor() {
super();
}
sanitize(html) {
return html;
}
bypassSecurityTrustHtml(value: string): any {
return value;
}
bypassSecurityTrustStyle(value: string): any {
return null;
}
bypassSecurityTrustScript(value: string): any {
return null;
}
bypassSecurityTrustUrl(value: string): any {
return null;
}
bypassSecurityTrustResourceUrl(value: string): any {
return null;
}
}
describe('ShareDataTableAdapter', () => {
let documentListService: DocumentListService;
let thumbnailService: ThumbnailService;
let contentService: ContentService;
const fakeMatIconRegistry: MatIconRegistry = jasmine.createSpyObj(['addSvgIcon', 'addSvgIconInNamespace']);
beforeEach(() => {
const imageUrl: string = 'http://<addresss>';
contentService = new ContentService(null, null, null, null);
documentListService = new DocumentListService(null, contentService, null, null, null);
spyOn(documentListService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
thumbnailService = new ThumbnailService(contentService, fakeMatIconRegistry, new FakeSanitizer());
spyOn(thumbnailService, 'getDocumentThumbnailUrl').and.returnValue(imageUrl);
});
it('should use client sorting by default', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, []);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
expect(adapter.sortingMode).toBe('client');
});
it('should not be case sensitive for sorting mode value', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, []);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
adapter.sortingMode = 'CLIENT';
expect(adapter.sortingMode).toBe('client');
@ -49,7 +82,7 @@ describe('ShareDataTableAdapter', () => {
});
it('should fallback to client sorting for unknown values', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, []);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, []);
adapter.sortingMode = 'SeRvEr';
expect(adapter.sortingMode).toBe('server');
@ -60,27 +93,27 @@ describe('ShareDataTableAdapter', () => {
it('should setup rows and columns with constructor', () => {
const schema = [<DataColumn> {}];
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, schema);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, schema);
expect(adapter.getRows()).toEqual([]);
expect(adapter.getColumns()).toEqual(schema);
});
it('should setup columns when constructor is missing schema', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
expect(adapter.getColumns()).toEqual([]);
});
it('should set new columns', () => {
const columns = [<DataColumn> {}, <DataColumn> {}];
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
adapter.setColumns(columns);
expect(adapter.getColumns()).toEqual(columns);
});
it('should reset columns', () => {
const columns = [<DataColumn> {}, <DataColumn> {}];
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, columns);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, columns);
expect(adapter.getColumns()).toEqual(columns);
adapter.setColumns(null);
@ -89,7 +122,7 @@ describe('ShareDataTableAdapter', () => {
it('should set new rows', () => {
const rows = [<DataRow> {}, <DataRow> {}];
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
expect(adapter.getRows()).toEqual([]);
adapter.setRows(rows);
@ -98,7 +131,7 @@ describe('ShareDataTableAdapter', () => {
it('should reset rows', () => {
const rows = [<DataRow> {}, <DataRow> {}];
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
adapter.setRows(rows);
expect(adapter.getRows()).toEqual(rows);
@ -108,7 +141,7 @@ describe('ShareDataTableAdapter', () => {
});
it('should sort new rows', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
spyOn(adapter, 'sort').and.callThrough();
const rows = [<DataRow> {}];
@ -118,7 +151,7 @@ describe('ShareDataTableAdapter', () => {
});
it('should fail when getting value for missing row', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const check = () => {
return adapter.getValue(null, <DataColumn> {});
};
@ -126,7 +159,7 @@ describe('ShareDataTableAdapter', () => {
});
it('should fail when getting value for missing column', () => {
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const check = () => {
return adapter.getValue(<DataRow> {}, null);
};
@ -145,16 +178,16 @@ describe('ShareDataTableAdapter', () => {
};
const row = new ShareDataRow(file, contentService, null);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const value = adapter.getValue(row, col);
expect(value).toBe(rawValue);
});
it('should generate fallback icon for a file thumbnail with missing mime type', () => {
spyOn(documentListService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
spyOn(thumbnailService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const file = new FileNode();
file.entry.content.mimeType = null;
@ -168,9 +201,9 @@ describe('ShareDataTableAdapter', () => {
});
it('should generate fallback icon for a file with no content entry', () => {
spyOn(documentListService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
spyOn(thumbnailService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const file = new FileNode();
file.entry.content = null;
@ -189,7 +222,7 @@ describe('ShareDataTableAdapter', () => {
const file = new FileNode();
file.entry['icon'] = imageUrl;
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(file, contentService, null);
const col = <DataColumn> { type: 'image', key: 'icon' };
@ -198,9 +231,9 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve folder icon', () => {
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder.svg`);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new FolderNode(), contentService, null);
const col = <DataColumn> { type: 'image', key: '$thumbnail' };
@ -211,9 +244,9 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve smart folder icon', () => {
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_smart_folder.svg`);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_smart_folder.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new SmartFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' };
@ -224,9 +257,9 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve link folder icon', () => {
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_shortcut_link.svg`);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_shortcut_link.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new LinkFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' };
@ -237,9 +270,9 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve rule folder icon', () => {
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_rule.svg`);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_rule.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const row = new ShareDataRow(new RuleFolderNode(), contentService, null);
const col = <DataColumn> { type: 'folder', key: '$thumbnail' };
@ -251,7 +284,7 @@ describe('ShareDataTableAdapter', () => {
it('should resolve file thumbnail', () => {
const imageUrl = 'http://<addresss>';
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
adapter.thumbnails = true;
const file = new FileNode();
@ -260,13 +293,13 @@ describe('ShareDataTableAdapter', () => {
const value = adapter.getValue(row, col);
expect(value).toBe(imageUrl);
expect(documentListService.getDocumentThumbnailUrl).toHaveBeenCalledWith(file);
expect(thumbnailService.getDocumentThumbnailUrl).toHaveBeenCalledWith(file);
});
it('should resolve fallback file icon for unknown node', () => {
spyOn(documentListService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
spyOn(thumbnailService, 'getDefaultMimeTypeIcon').and.returnValue(`assets/images/ft_ic_miscellaneous.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const file = new FileNode();
file.entry.isFile = false;
@ -282,8 +315,8 @@ describe('ShareDataTableAdapter', () => {
});
it('should resolve file icon for content type', () => {
spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_raster_image.svg`);
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, null);
spyOn(thumbnailService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_raster_image.svg`);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, null);
const file = new FileNode();
file.entry.isFile = false;
@ -304,7 +337,7 @@ describe('ShareDataTableAdapter', () => {
const folder = new FolderNode();
const col = <DataColumn> { key: 'name' };
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, [col]);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, [col]);
adapter.setSorting(new DataSorting('name', 'asc'));
adapter.setRows([
@ -327,7 +360,7 @@ describe('ShareDataTableAdapter', () => {
file2.entry['dateProp'] = new Date(2016, 6, 30, 13, 14, 2);
const col = <DataColumn> { key: 'dateProp' };
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, [col]);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, [col]);
adapter.setRows([
new ShareDataRow(file2, contentService, null),
@ -357,7 +390,7 @@ describe('ShareDataTableAdapter', () => {
file4.entry.content.sizeInBytes = 2852791665; // 2.66 GB
const col = <DataColumn> { key: 'content.sizeInBytes' };
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, [col]);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, [col]);
adapter.setRows([
new ShareDataRow(file3, contentService, null),
@ -390,7 +423,7 @@ describe('ShareDataTableAdapter', () => {
const file6 = new FileNode('b');
const col = <DataColumn> { key: 'name' };
const adapter = new ShareDataTableAdapter(documentListService, null, contentService, [col]);
const adapter = new ShareDataTableAdapter(thumbnailService, contentService, [col]);
adapter.setRows([
new ShareDataRow(file4, contentService, null),

View File

@ -25,7 +25,6 @@ import {
} from '@alfresco/adf-core';
import { NodePaging } from '@alfresco/js-api';
import { PermissionStyleModel } from './../models/permissions-style.model';
import { DocumentListService } from './../services/document-list.service';
import { ShareDataRow } from './share-data-row.model';
import { NodeEntry } from '@alfresco/js-api/src/api/content-rest-api/model/nodeEntry';
import { RowFilter } from './row-filter.model';
@ -59,8 +58,7 @@ export class ShareDataTableAdapter implements DataTableAdapter {
return this._sortingMode;
}
constructor(private documentListService: DocumentListService,
private thumbnailService: ThumbnailService,
constructor(private thumbnailService: ThumbnailService,
private contentService: ContentService,
schema: DataColumn[] = [],
sorting?: DataSorting,
@ -119,18 +117,18 @@ export class ShareDataTableAdapter implements DataTableAdapter {
if (node.entry.isFile) {
if (this.thumbnails) {
return this.documentListService.getDocumentThumbnailUrl(node);
return this.thumbnailService.getDocumentThumbnailUrl(node);
}
}
if (node.entry.content) {
const mimeType = node.entry.content.mimeType;
if (mimeType) {
return this.documentListService.getMimeTypeIcon(mimeType);
return this.thumbnailService.getMimeTypeIcon(mimeType);
}
}
return this.documentListService.getDefaultMimeTypeIcon();
return this.thumbnailService.getDefaultMimeTypeIcon();
}
if (col.type === 'image') {
@ -175,13 +173,13 @@ export class ShareDataTableAdapter implements DataTableAdapter {
private getFolderIcon(node: any) {
if (this.isSmartFolder(node)) {
return this.documentListService.getMimeTypeIcon('smartFolder');
return this.thumbnailService.getMimeTypeIcon('smartFolder');
} else if (this.isRuleFolder(node)) {
return this.documentListService.getMimeTypeIcon('ruleFolder');
return this.thumbnailService.getMimeTypeIcon('ruleFolder');
} else if (this.isALinkFolder(node)) {
return this.documentListService.getMimeTypeIcon('linkFolder');
return this.thumbnailService.getMimeTypeIcon('linkFolder');
} else {
return this.documentListService.getMimeTypeIcon('folder');
return this.thumbnailService.getMimeTypeIcon('folder');
}
}

View File

@ -0,0 +1,25 @@
/*!
* @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 { PaginationModel } from '@alfresco/adf-core';
import { Observable } from 'rxjs';
import { DocumentLoaderNode } from '../models/document-folder.model';
export interface DocumentListLoader {
loadFolderByNodeId(nodeId: string, pagination: PaginationModel, includeFields: string[], where?: string): Observable <DocumentLoaderNode>;
}

View File

@ -0,0 +1,28 @@
/*!
* @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 { NodeEntry, NodePaging } from '@alfresco/js-api';
export class DocumentLoaderNode {
currentNode: NodeEntry;
children: NodePaging;
constructor(currentNode: NodeEntry, children: NodePaging) {
this.currentNode = currentNode;
this.children = children;
}
}

View File

@ -46,4 +46,6 @@ export * from './models/document-library.model';
export * from './models/permissions.model';
export * from './models/permissions-style.model';
export * from './interfaces/document-list-loader.interface';
export * from './document-list.module';

View File

@ -39,7 +39,7 @@ describe('DocumentActionsService', () => {
const contentService = new ContentService(null, null, null, null);
const alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService());
documentListService = new DocumentListService(null, contentService, alfrescoApiService, null, null);
documentListService = new DocumentListService(contentService, alfrescoApiService, null, null);
service = new DocumentActionsService(null, null, new TranslationMock(), documentListService, contentService);
});

View File

@ -18,6 +18,7 @@
import { AlfrescoApiServiceMock, AlfrescoApiService,
AppConfigService, StorageService, ContentService, setupTestBed, CoreModule, LogService, AppConfigServiceMock } from '@alfresco/adf-core';
import { DocumentListService } from './document-list.service';
import { CustomResourcesService } from './custom-resources.service';
declare let jasmine: any;
@ -70,7 +71,8 @@ describe('DocumentListService', () => {
const logService = new LogService(new AppConfigServiceMock(null));
const contentService = new ContentService(null, null, null, null);
alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService());
service = new DocumentListService(null, contentService, alfrescoApiService, logService, null);
const customActionService = new CustomResourcesService(alfrescoApiService, logService);
service = new DocumentListService(contentService, alfrescoApiService, logService, customActionService);
jasmine.Ajax.install();
});

View File

@ -16,26 +16,28 @@
*/
import {
AlfrescoApiService, AuthenticationService, ContentService, LogService, ThumbnailService
AlfrescoApiService, ContentService, LogService, PaginationModel
} from '@alfresco/adf-core';
import { Injectable } from '@angular/core';
import { NodeEntry, NodePaging } from '@alfresco/js-api';
import { Observable, from, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { DocumentLoaderNode } from '../models/document-folder.model';
import { Observable, from, throwError, forkJoin } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { DocumentListLoader } from '../interfaces/document-list-loader.interface';
import { CustomResourcesService } from './custom-resources.service';
@Injectable({
providedIn: 'root'
})
export class DocumentListService {
export class DocumentListService implements DocumentListLoader {
static ROOT_ID = '-root-';
constructor(authService: AuthenticationService,
private contentService: ContentService,
constructor(private contentService: ContentService,
private apiService: AlfrescoApiService,
private logService: LogService,
private thumbnailService: ThumbnailService) {
private customResourcesService: CustomResourcesService) {
}
/**
@ -155,30 +157,31 @@ export class DocumentListService {
);
}
/**
* Get thumbnail URL for the given document node.
* @param node Node to get URL for.
* @returns Thumbnail URL string
*/
getDocumentThumbnailUrl(node: NodeEntry): string {
return this.thumbnailService.getDocumentThumbnailUrl(node);
isCustomSourceService(nodeId): boolean {
return this.customResourcesService.isCustomSource(nodeId);
}
/**
* Gets the icon that represents a MIME type.
* @param mimeType MIME type to get the icon for
* @returns Path to the icon file
*/
getMimeTypeIcon(mimeType: string): string {
return this.thumbnailService.getMimeTypeIcon(mimeType);
loadFolderByNodeId(nodeId: string, pagination: PaginationModel, includeFields: string[], where?: string): Observable<DocumentLoaderNode> {
if (this.customResourcesService.isCustomSource(nodeId)) {
return this.customResourcesService.loadFolderByNodeId(nodeId, pagination, includeFields).pipe(
map((result: any) => new DocumentLoaderNode(null, result))
);
} else {
return this.retrieveDocumentNode(nodeId, pagination, includeFields, where);
}
}
/**
* Gets a default icon for MIME types with no specific icon.
* @returns Path to the icon file
*/
getDefaultMimeTypeIcon(): string {
return this.thumbnailService.getDefaultMimeTypeIcon();
private retrieveDocumentNode(nodeId: string, pagination: PaginationModel, includeFields: string[], where?: string): Observable<DocumentLoaderNode> {
return forkJoin(
this.getFolderNode(nodeId, includeFields),
this.getFolder(null, {
maxItems: pagination.maxItems,
skipCount: pagination.skipCount,
rootFolderId: nodeId,
where: where
}, includeFields)).pipe(
map((results) => new DocumentLoaderNode(results[0], results[1]))
);
}
private handleError(error: any) {

View File

@ -40,7 +40,7 @@ describe('FolderActionsService', () => {
const contentService = new ContentService(null, null, null, null);
const alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService());
documentListService = new DocumentListService(null, contentService, alfrescoApiService, null, null);
documentListService = new DocumentListService(contentService, alfrescoApiService, null, null);
service = new FolderActionsService(null, documentListService, contentService, new TranslationMock());
});