diff --git a/docs/content-services/document-list.component.md b/docs/content-services/document-list.component.md index 1f60297206..e580b92edd 100644 --- a/docs/content-services/document-list.component.md +++ b/docs/content-services/document-list.component.md @@ -99,6 +99,9 @@ Displays the documents from a repository. The properties `currentFolderId`, `folderNode` and `node` set the initial folder shown by the Document List. They cannot be used together, so choose the one that suits your use case best. +Document list will automatically show special icons for : `Smart Folder`, `Link to a Folder` and `Folder with rules` as showed in the picture below : + +![Document List Folders](../docassets/images/document-list-special-folder-icon.png) ### DOM Events diff --git a/docs/docassets/images/document-list-special-folder-icon.png b/docs/docassets/images/document-list-special-folder-icon.png new file mode 100644 index 0000000000..f4d61fe297 Binary files /dev/null and b/docs/docassets/images/document-list-special-folder-icon.png differ diff --git a/lib/content-services/document-list/components/document-list.component.spec.ts b/lib/content-services/document-list/components/document-list.component.spec.ts index 6b038961f7..9836040a65 100644 --- a/lib/content-services/document-list/components/document-list.component.spec.ts +++ b/lib/content-services/document-list/components/document-list.component.spec.ts @@ -720,6 +720,18 @@ describe('DocumentList', () => { expect(documentList.performNavigation(null)).toBeFalsy(); }); + it('should perform navigation through corret linked folder', () => { + let linkFolder = new FolderNode(); + linkFolder.entry.id = 'link-folder'; + linkFolder.entry.nodeType = 'app:folderlink'; + linkFolder.entry.properties['cm:destination'] = 'normal-folder'; + + spyOn(documentList, 'loadFolder').and.stub(); + + expect(documentList.performNavigation(linkFolder)).toBeTruthy(); + expect(documentList.currentFolderId).toBe('normal-folder'); + }); + it('should require valid node for file preview', () => { let file = new FileNode(); file.entry = null; @@ -977,6 +989,16 @@ describe('DocumentList', () => { documentList.loadFolderByNodeId('123'); }); + it('should emit folderChange event when a folder node is clicked', (done) => { + spyOn(documentList, 'reload').and.stub(); + + documentList.folderChange.subscribe((folderNode) => { + expect(folderNode.value.id).toBe('fake-node'); + done(); + }); + documentList.onNodeDblClick({ entry: { id: 'fake-node', isFolder: true } }); + }); + it('should set no permission when getFolderNode fails with 403', (done) => { const error = { message: '{ "error": { "statusCode": 403 } }' }; spyOn(documentListService, 'getFolderNode').and.returnValue(throwError(error)); diff --git a/lib/content-services/document-list/components/document-list.component.ts b/lib/content-services/document-list/components/document-list.component.ts index b2afc3ab9d..2abf9aede5 100644 --- a/lib/content-services/document-list/components/document-list.component.ts +++ b/lib/content-services/document-list/components/document-list.component.ts @@ -539,9 +539,18 @@ export class DocumentListComponent implements OnInit, OnChanges, OnDestroy, Afte updateFolderData(node: MinimalNodeEntity): void { this.resetNewFolderPagination(); - this.currentFolderId = node.entry.id; + this.currentFolderId = this.getNodeFolderDestinationId(node); + this.folderChange.emit(new NodeEntryEvent({ id: this.currentFolderId })); this.reload(); - this.folderChange.emit(new NodeEntryEvent(node.entry)); + } + + private getNodeFolderDestinationId(node: MinimalNodeEntity) { + return this.isLinkFolder(node) ? node.entry.properties['cm:destination'] : node.entry.id; + } + + private isLinkFolder(node: MinimalNodeEntity) { + return node.entry.nodeType === 'app:folderlink' && node.entry.properties && + node.entry.properties['cm:destination']; } updateCustomSourceData(nodeId: string): void { diff --git a/lib/content-services/document-list/data/share-datatable-adapter.spec.ts b/lib/content-services/document-list/data/share-datatable-adapter.spec.ts index 74cb473593..3c17a55394 100644 --- a/lib/content-services/document-list/data/share-datatable-adapter.spec.ts +++ b/lib/content-services/document-list/data/share-datatable-adapter.spec.ts @@ -16,7 +16,7 @@ */ import { DataColumn, DataRow, DataSorting, ContentService } from '@alfresco/adf-core'; -import { FileNode, FolderNode, SmartFolderNode } from './../../mock'; +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'; @@ -222,6 +222,32 @@ describe('ShareDataTableAdapter', () => { expect(value).toContain(`svg`); }); + it('should resolve link folder icon', () => { + spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_shortcut_link.svg`); + + let adapter = new ShareDataTableAdapter(documentListService, null, null); + + let row = new ShareDataRow(new LinkFolderNode(), documentListService, null); + let col = { type: 'folder', key: '$thumbnail' }; + + let value = adapter.getValue(row, col); + expect(value).toContain(`assets/images/ft_ic_folder_shortcut_link`); + expect(value).toContain(`svg`); + }); + + it('should resolve rule folder icon', () => { + spyOn(documentListService, 'getMimeTypeIcon').and.returnValue(`assets/images/ft_ic_folder_rule.svg`); + + let adapter = new ShareDataTableAdapter(documentListService, null, null); + + let row = new ShareDataRow(new RuleFolderNode(), documentListService, null); + let col = { type: 'folder', key: '$thumbnail' }; + + let value = adapter.getValue(row, col); + expect(value).toContain(`assets/images/ft_ic_folder_rule`); + expect(value).toContain(`svg`); + }); + it('should resolve file thumbnail', () => { let imageUrl = 'http://'; let adapter = new ShareDataTableAdapter(documentListService, null, null); diff --git a/lib/content-services/document-list/data/share-datatable-adapter.ts b/lib/content-services/document-list/data/share-datatable-adapter.ts index b5fbbc4490..16bd5249e3 100644 --- a/lib/content-services/document-list/data/share-datatable-adapter.ts +++ b/lib/content-services/document-list/data/share-datatable-adapter.ts @@ -104,11 +104,7 @@ export class ShareDataTableAdapter implements DataTableAdapter { const node = ( row).node; if (node.entry.isFolder) { - if (this.isSmartFolder(node)) { - return this.documentListService.getMimeTypeIcon('smartFolder'); - } else { - return this.documentListService.getMimeTypeIcon('folder'); - } + return this.getFolderIcon(node); } if (node.entry.isFile) { @@ -167,12 +163,35 @@ export class ShareDataTableAdapter implements DataTableAdapter { this.imageResolver = resolver; } + private getFolderIcon(node: any) { + if (this.isSmartFolder(node)) { + return this.documentListService.getMimeTypeIcon('smartFolder'); + } else if (this.isRuleFolder(node)) { + return this.documentListService.getMimeTypeIcon('ruleFolder'); + } else if (this.isALinkFolder(node)) { + return this.documentListService.getMimeTypeIcon('linkFolder'); + } else { + return this.documentListService.getMimeTypeIcon('folder'); + } + } + isSmartFolder(node: any) { let nodeAspects = this.getNodeAspectNames(node); return nodeAspects.indexOf('smf:customConfigSmartFolder') > -1 || (nodeAspects.indexOf('smf:systemConfigSmartFolder') > -1); } + isRuleFolder(node: any) { + let nodeAspects = this.getNodeAspectNames(node); + return nodeAspects.indexOf('rule:rules') > -1 || + (nodeAspects.indexOf('rule:rules') > -1); + } + + isALinkFolder(node: any) { + const nodeType = node.entry ? node.entry.nodeType : node.nodeType; + return nodeType === 'app:folderlink'; + } + private getNodeAspectNames(node: any): any[] { return node.entry && node.entry.aspectNames ? node.entry.aspectNames : node.aspectNames ? node.aspectNames : []; } diff --git a/lib/content-services/mock/document-library.model.mock.ts b/lib/content-services/mock/document-library.model.mock.ts index 2a4b5209d9..54d449b6e6 100644 --- a/lib/content-services/mock/document-library.model.mock.ts +++ b/lib/content-services/mock/document-library.model.mock.ts @@ -71,3 +71,29 @@ export class SmartFolderNode extends NodeMinimalEntry { this.entry.aspectNames = ['smf:systemConfigSmartFolder']; } } + +export class RuleFolderNode extends NodeMinimalEntry { + constructor(name?: string) { + super(); + this.entry = new NodeMinimal(); + this.entry.id = 'rule-folder-id'; + this.entry.isFile = false; + this.entry.isFolder = true; + this.entry.name = name; + this.entry.path = new PathInfoEntity(); + this.entry.aspectNames = ['rule:rules']; + } +} + +export class LinkFolderNode extends NodeMinimalEntry { + constructor(name?: string) { + super(); + this.entry = new NodeMinimal(); + this.entry.id = 'link-folder-id'; + this.entry.isFile = false; + this.entry.isFolder = true; + this.entry.nodeType = 'app:folderlink'; + this.entry.name = name; + this.entry.path = new PathInfoEntity(); + } +} diff --git a/lib/core/assets/images/ft_ic_folder_rule.svg b/lib/core/assets/images/ft_ic_folder_rule.svg new file mode 100644 index 0000000000..7b4e8b1af3 --- /dev/null +++ b/lib/core/assets/images/ft_ic_folder_rule.svg @@ -0,0 +1,18 @@ + + + + folder-with-rule copy + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/core/assets/images/ft_ic_folder_shortcut_link.svg b/lib/core/assets/images/ft_ic_folder_shortcut_link.svg new file mode 100644 index 0000000000..efc8bd8e26 --- /dev/null +++ b/lib/core/assets/images/ft_ic_folder_shortcut_link.svg @@ -0,0 +1,18 @@ + + + + folder-shortcut-link copy + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/core/services/thumbnail.service.ts b/lib/core/services/thumbnail.service.ts index 5f59037e9d..57e60ff38c 100644 --- a/lib/core/services/thumbnail.service.ts +++ b/lib/core/services/thumbnail.service.ts @@ -149,6 +149,8 @@ export class ThumbnailService { 'application/x-cpio': './assets/images/ft_ic_document.svg', 'folder': './assets/images/ft_ic_folder.svg', 'smartFolder': './assets/images/ft_ic_smart_folder.svg', + 'ruleFolder': './assets/images/ft_ic_folder_rule.svg', + 'linkFolder': './assets/images/ft_ic_folder_shortcut_link.svg', 'disable/folder': './assets/images/ft_ic_folder_disable.svg', 'selected': './assets/images/ft_ic_selected.svg' };