From 9dba816877ad9d80edc4c9fe94cf2170588641d0 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 3 Jan 2019 14:07:07 +0000 Subject: [PATCH] [ADF-3869] extensibility related components (#4107) * extensions: dynamic column * content: trashcan name column * content: library status column * content: library role column * content: library name column * style fixes * content: name column * demo: use name column in DL example * fix tests * lint fixes * code fixes * update docs * add toggle to demo shell --- .../app/components/files/files.component.html | 27 ++++- .../app/components/files/files.component.ts | 1 + .../document-list.component.md | 23 ++++ .../dialogs/library/library.dialog.ts | 13 ++- .../library-name-column.component.spec.ts | 96 ++++++++++++++++ .../library-name-column.component.ts | 90 +++++++++++++++ .../library-role-column.component.spec.ts | 77 +++++++++++++ .../library-role-column.component.ts | 58 ++++++++++ .../library-status-column.component.spec.ts | 24 ++++ .../library-status-column.component.ts | 56 +++++++++ .../name-column/name-column.component.spec.ts | 24 ++++ .../name-column/name-column.component.ts | 65 +++++++++++ .../trashcan-name-column.component.spec.ts | 106 ++++++++++++++++++ .../trashcan-name-column.component.ts | 87 ++++++++++++++ .../document-list/document-list.module.ts | 15 +++ lib/content-services/i18n/de.json | 6 + lib/content-services/i18n/en.json | 6 + lib/content-services/i18n/es.json | 6 + lib/content-services/i18n/fr.json | 6 + lib/content-services/i18n/it.json | 6 + lib/content-services/i18n/ja.json | 6 + lib/content-services/i18n/nb.json | 6 + lib/content-services/i18n/nl.json | 6 + lib/content-services/i18n/pt-BR.json | 6 + lib/content-services/i18n/ru.json | 6 + lib/content-services/i18n/zh-CN.json | 6 + .../datatable/datatable.component.scss | 10 ++ .../dynamic-column.component.ts | 100 +++++++++++++++++ lib/extensions/src/lib/extensions.module.ts | 13 ++- 29 files changed, 940 insertions(+), 11 deletions(-) create mode 100644 lib/content-services/document-list/components/library-name-column/library-name-column.component.spec.ts create mode 100644 lib/content-services/document-list/components/library-name-column/library-name-column.component.ts create mode 100644 lib/content-services/document-list/components/library-role-column/library-role-column.component.spec.ts create mode 100644 lib/content-services/document-list/components/library-role-column/library-role-column.component.ts create mode 100644 lib/content-services/document-list/components/library-status-column/library-status-column.component.spec.ts create mode 100644 lib/content-services/document-list/components/library-status-column/library-status-column.component.ts create mode 100644 lib/content-services/document-list/components/name-column/name-column.component.spec.ts create mode 100644 lib/content-services/document-list/components/name-column/name-column.component.ts create mode 100644 lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.spec.ts create mode 100644 lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.ts create mode 100644 lib/extensions/src/lib/components/dynamic-column/dynamic-column.component.ts diff --git a/demo-shell/src/app/components/files/files.component.html b/demo-shell/src/app/components/files/files.component.html index 9518ca1f05..7c7f708daf 100644 --- a/demo-shell/src/app/components/files/files.component.html +++ b/demo-shell/src/app/components/files/files.component.html @@ -224,7 +224,8 @@ (ready)="emitReadyEvent($event)" (preview)="showFile($event)" (folderChange)="onFolderChange($event)" - (permissionError)="handlePermissionError($event)"> + (permissionError)="handlePermissionError($event)" + (name-click)="documentList.onNodeDblClick($event.detail?.node)">

You don't have permissions

@@ -246,7 +247,17 @@ [class.adf-cell-thumbnail]="thumbnails"> + + + + + + (execute)="startProcessAction($event)"> +
+ + Hyperlink navigation + +
+
{{'DOCUMENT_LIST.MULTISELECT_CHECKBOXES' | translate}} diff --git a/demo-shell/src/app/components/files/files.component.ts b/demo-shell/src/app/components/files/files.component.ts index 69daf2e1ea..ad3b6f8abc 100644 --- a/demo-shell/src/app/components/files/files.component.ts +++ b/demo-shell/src/app/components/files/files.component.ts @@ -187,6 +187,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy { enableCustomPermissionMessage = false; enableMediumTimeFormat = false; displayEmptyMetadata = false; + hyperlinkNavigation = false; private onCreateFolder: Subscription; private onEditFolder: Subscription; diff --git a/docs/content-services/document-list.component.md b/docs/content-services/document-list.component.md index 0124fd6142..9a7daea012 100644 --- a/docs/content-services/document-list.component.md +++ b/docs/content-services/document-list.component.md @@ -557,6 +557,29 @@ You can also use the HTML-based schema declaration used by You can also add tooltips, styling, automatic column title translation and other features. See the [DataColumn component page](../core/data-column.component.md) for more information about specifying and customizing columns. +### Column templates + +You can use the following components as column templates: + +* adf-name-column +* adf-library-name-column +* adf-library-role-column +* adf-library-status-column + +All components above require `context` property to be bound. +For example: + +```html + + + + + +``` + ### Date Column For the `date` column type, the Angular [DatePipe](https://angular.io/docs/ts/latest/api/common/DatePipe-class.html) formatting is used. diff --git a/lib/content-services/dialogs/library/library.dialog.ts b/lib/content-services/dialogs/library/library.dialog.ts index 33f99af0a0..00c93961dd 100644 --- a/lib/content-services/dialogs/library/library.dialog.ts +++ b/lib/content-services/dialogs/library/library.dialog.ts @@ -199,7 +199,13 @@ export class LibraryDialogComponent implements OnInit, OnDestroy { } private async checkLibraryNameExists(libraryTitle: string) { - const { entries } = (await this.findLibraryByTitle(libraryTitle)).list; + let entries = []; + + try { + entries = (await this.findLibraryByTitle(libraryTitle)).list.entries; + } catch { + entries = []; + } if (entries.length) { this.libraryTitleExists = entries[0].entry.title.toLowerCase() === libraryTitle.toLowerCase(); @@ -208,14 +214,13 @@ export class LibraryDialogComponent implements OnInit, OnDestroy { } } - private findLibraryByTitle(libraryTitle: string): Promise { + private async findLibraryByTitle(libraryTitle: string): Promise { return this.alfrescoApiService .getInstance() .core.queriesApi.findSites(libraryTitle, { maxItems: 1, fields: ['title'] - }) - .catch(() => ({ list: { entries: [] } })); + }); } private forbidSpecialCharacters({ value }: FormControl) { diff --git a/lib/content-services/document-list/components/library-name-column/library-name-column.component.spec.ts b/lib/content-services/document-list/components/library-name-column/library-name-column.component.spec.ts new file mode 100644 index 0000000000..9df80b3db5 --- /dev/null +++ b/lib/content-services/document-list/components/library-name-column/library-name-column.component.spec.ts @@ -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, ComponentFixture } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { setupTestBed } from '@alfresco/adf-core'; +import { LibraryNameColumnComponent } from './library-name-column.component'; +import { ContentTestingModule } from '../../../testing/content.testing.module'; + +describe('LibraryNameColumnComponent', () => { + let fixture: ComponentFixture; + let component: LibraryNameColumnComponent; + let node; + + setupTestBed({ + imports: [ContentTestingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA] + }); + + beforeEach(() => { + node = { + id: 'nodeId', + path: { + elements: [] + } + }; + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LibraryNameColumnComponent); + component = fixture.componentInstance; + }); + + describe('makeLibraryTooltip()', () => { + it('maps tooltip to description', () => { + node.description = 'description'; + const tooltip = component.makeLibraryTooltip(node); + + expect(tooltip).toBe(node.description); + }); + + it('maps tooltip to description', () => { + node.title = 'title'; + const tooltip = component.makeLibraryTooltip(node); + + expect(tooltip).toBe(node.title); + }); + + it('sets tooltip to empty string', () => { + const tooltip = component.makeLibraryTooltip(node); + + expect(tooltip).toBe(''); + }); + }); + + describe('makeLibraryTitle()', () => { + it('sets title with id when duplicate nodes title exists in list', () => { + node.title = 'title'; + + const rows = [ + { node: { entry: { id: 'some-id', title: 'title' } } } + ]; + + const title = component.makeLibraryTitle(node, rows); + expect(title).toContain('nodeId'); + }); + + it('sets title when no duplicate nodes title exists in list', () => { + node.title = 'title'; + + const rows = [ + { + node: { entry: { id: 'some-id', title: 'title-some-id' } } + } + ]; + + const title = component.makeLibraryTitle(node, rows); + + expect(title).toBe('title'); + }); + }); +}); diff --git a/lib/content-services/document-list/components/library-name-column/library-name-column.component.ts b/lib/content-services/document-list/components/library-name-column/library-name-column.component.ts new file mode 100644 index 0000000000..7208d39b51 --- /dev/null +++ b/lib/content-services/document-list/components/library-name-column/library-name-column.component.ts @@ -0,0 +1,90 @@ +/*! + * @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, + ChangeDetectionStrategy, + ViewEncapsulation, + OnInit, + Input, + ElementRef +} from '@angular/core'; +import { MinimalNodeEntity } from 'alfresco-js-api'; +import { ShareDataRow } from '../../data/share-data-row.model'; + +@Component({ + selector: 'adf-library-name-column', + template: ` + + {{ displayText }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { class: 'adf-datatable-cell adf-datatable-link adf-library-name-column' } +}) +export class LibraryNameColumnComponent implements OnInit { + @Input() + context: any; + + displayTooltip: string; + displayText: string; + node: MinimalNodeEntity; + + constructor(private element: ElementRef) {} + + ngOnInit() { + this.node = this.context.row.node; + const rows: Array = this.context.data.rows || []; + if (this.node && this.node.entry) { + this.displayText = this.makeLibraryTitle(this.node.entry, rows); + this.displayTooltip = this.makeLibraryTooltip(this.node.entry); + } + } + + onClick() { + this.element.nativeElement.dispatchEvent( + new CustomEvent('name-click', { + bubbles: true, + detail: { + node: this.node + } + }) + ); + } + + makeLibraryTooltip(library: any): string { + const { description, title } = library; + + return description || title || ''; + } + + makeLibraryTitle(library: any, rows: Array): string { + const entries = rows.map((r: ShareDataRow) => r.node.entry); + const { title, id } = library; + + let isDuplicate = false; + + if (entries) { + isDuplicate = entries.some((entry: any) => { + return entry.id !== id && entry.title === title; + }); + } + + return isDuplicate ? `${title} (${id})` : `${title}`; + } +} diff --git a/lib/content-services/document-list/components/library-role-column/library-role-column.component.spec.ts b/lib/content-services/document-list/components/library-role-column/library-role-column.component.spec.ts new file mode 100644 index 0000000000..89fb771acb --- /dev/null +++ b/lib/content-services/document-list/components/library-role-column/library-role-column.component.spec.ts @@ -0,0 +1,77 @@ +/*! + * @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 { setupTestBed } from '@alfresco/adf-core'; +import { LibraryRoleColumnComponent } from './library-role-column.component'; +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { NO_ERRORS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { ContentTestingModule } from '../../../testing/content.testing.module'; + +describe('LibraryNameColumnComponent', () => { + let fixture: ComponentFixture; + let component: LibraryRoleColumnComponent; + + setupTestBed({ + imports: [ContentTestingModule], + schemas: [CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LibraryRoleColumnComponent); + component = fixture.componentInstance; + }); + + it('should render Manager', () => { + component.context = { + row: { node: { entry: { role: 'SiteManager' } } } + }; + fixture.detectChanges(); + expect(component.displayText).toBe('LIBRARY.ROLE.MANAGER'); + }); + + it('should render Collaborator', () => { + component.context = { + row: { node: { entry: { role: 'SiteCollaborator' } } } + }; + fixture.detectChanges(); + expect(component.displayText).toBe('LIBRARY.ROLE.COLLABORATOR'); + }); + + it('should render Contributor', () => { + component.context = { + row: { node: { entry: { role: 'SiteContributor' } } } + }; + fixture.detectChanges(); + expect(component.displayText).toBe('LIBRARY.ROLE.CONTRIBUTOR'); + }); + + it('should render Consumer', () => { + component.context = { + row: { node: { entry: { role: 'SiteConsumer' } } } + }; + fixture.detectChanges(); + expect(component.displayText).toBe('LIBRARY.ROLE.CONSUMER'); + }); + + it('should not render text for unknown', () => { + component.context = { + row: { node: { entry: { role: 'ROLE' } } } + }; + fixture.detectChanges(); + expect(component.displayText).toBe(''); + }); +}); diff --git a/lib/content-services/document-list/components/library-role-column/library-role-column.component.ts b/lib/content-services/document-list/components/library-role-column/library-role-column.component.ts new file mode 100644 index 0000000000..c39357700b --- /dev/null +++ b/lib/content-services/document-list/components/library-role-column/library-role-column.component.ts @@ -0,0 +1,58 @@ +/*! + * @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, OnInit, Input } from '@angular/core'; + +@Component({ + selector: 'adf-library-role-column', + template: ` + + {{ displayText | translate }} + + `, + host: { class: 'adf-library-role-column' } +}) +export class LibraryRoleColumnComponent implements OnInit { + @Input() + context: any; + + displayText: string; + + ngOnInit() { + const node = this.context.row.node; + if (node && node.entry) { + const role: string = node.entry.role; + switch (role) { + case 'SiteManager': + this.displayText = 'LIBRARY.ROLE.MANAGER'; + break; + case 'SiteCollaborator': + this.displayText = 'LIBRARY.ROLE.COLLABORATOR'; + break; + case 'SiteContributor': + this.displayText = 'LIBRARY.ROLE.CONTRIBUTOR'; + break; + case 'SiteConsumer': + this.displayText = 'LIBRARY.ROLE.CONSUMER'; + break; + default: + this.displayText = ''; + break; + } + } + } +} diff --git a/lib/content-services/document-list/components/library-status-column/library-status-column.component.spec.ts b/lib/content-services/document-list/components/library-status-column/library-status-column.component.spec.ts new file mode 100644 index 0000000000..bbb0dc17aa --- /dev/null +++ b/lib/content-services/document-list/components/library-status-column/library-status-column.component.spec.ts @@ -0,0 +1,24 @@ +/*! + * @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 { LibraryStatusColumnComponent } from './library-status-column.component'; + +describe('LibraryStatusColumnComponent', () => { + it('should be defined', () => { + expect(LibraryStatusColumnComponent).toBeDefined(); + }); +}); diff --git a/lib/content-services/document-list/components/library-status-column/library-status-column.component.ts b/lib/content-services/document-list/components/library-status-column/library-status-column.component.ts new file mode 100644 index 0000000000..5bd6587381 --- /dev/null +++ b/lib/content-services/document-list/components/library-status-column/library-status-column.component.ts @@ -0,0 +1,56 @@ +/*! + * @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, OnInit } from '@angular/core'; + +@Component({ + selector: 'adf-library-status-column', + template: ` + + {{ displayText | translate }} + + `, + host: { class: 'adf-library-status-column' } +}) +export class LibraryStatusColumnComponent implements OnInit { + @Input() + context: any; + + displayText: string; + + ngOnInit() { + const node = this.context.row.node; + if (node && node.entry) { + const visibility: string = node.entry.visibility; + + switch (visibility.toUpperCase()) { + case 'PUBLIC': + this.displayText = 'LIBRARY.VISIBILITY.PUBLIC'; + break; + case 'PRIVATE': + this.displayText = 'LIBRARY.VISIBILITY.PRIVATE'; + break; + case 'MODERATED': + this.displayText = 'LIBRARY.VISIBILITY.MODERATED'; + break; + default: + this.displayText = 'UNKNOWN'; + break; + } + } + } +} diff --git a/lib/content-services/document-list/components/name-column/name-column.component.spec.ts b/lib/content-services/document-list/components/name-column/name-column.component.spec.ts new file mode 100644 index 0000000000..5733c8b744 --- /dev/null +++ b/lib/content-services/document-list/components/name-column/name-column.component.spec.ts @@ -0,0 +1,24 @@ +/*! + * @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 { NameColumnComponent } from './name-column.component'; + +describe('NameColumnComponent', () => { + it('should be defined', () => { + expect(NameColumnComponent).toBeDefined(); + }); +}); diff --git a/lib/content-services/document-list/components/name-column/name-column.component.ts b/lib/content-services/document-list/components/name-column/name-column.component.ts new file mode 100644 index 0000000000..5ca17874f9 --- /dev/null +++ b/lib/content-services/document-list/components/name-column/name-column.component.ts @@ -0,0 +1,65 @@ +/*! + * @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, + OnInit, + ChangeDetectionStrategy, + ViewEncapsulation, + ElementRef +} from '@angular/core'; +import { MinimalNodeEntity } from 'alfresco-js-api'; + +@Component({ + selector: 'adf-name-column', + template: ` + + {{ displayText }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { class: 'adf-datatable-cell adf-datatable-link adf-name-column' } +}) +export class NameColumnComponent implements OnInit { + @Input() + context: any; + + displayText: string; + node: MinimalNodeEntity; + + constructor(private element: ElementRef) {} + + ngOnInit() { + this.node = this.context.row.node; + if (this.node && this.node.entry) { + this.displayText = this.node.entry.name || this.node.entry.id; + } + } + + onClick() { + this.element.nativeElement.dispatchEvent( + new CustomEvent('name-click', { + bubbles: true, + detail: { + node: this.node + } + }) + ); + } +} diff --git a/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.spec.ts b/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.spec.ts new file mode 100644 index 0000000000..a41321b088 --- /dev/null +++ b/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.spec.ts @@ -0,0 +1,106 @@ +/*! + * @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 { TrashcanNameColumnComponent } from './trashcan-name-column.component'; + +describe('TrashcanNameColumnComponent', () => { + let component; + + beforeEach(() => { + component = new TrashcanNameColumnComponent(); + }); + + it('should set displayText for content files', () => { + const context = { + data: { rows: [] }, + row: { + node: { + entry: { + name: 'contentName', + nodeType: 'content' + } + } + } + }; + + component.context = context; + component.ngOnInit(); + + expect(component.displayText).toBe('contentName'); + }); + + it('should set displayText for library', () => { + const context = { + data: { + rows: [] + }, + row: { + node: { + entry: { + nodeType: 'st:site', + properties: { + 'cm:title': 'libraryTitle' + } + } + } + } + }; + + component.context = context; + component.ngOnInit(); + + expect(component.displayText).toBe('libraryTitle'); + }); + + it('should set custom displayText for libraries with same name', () => { + const context = { + data: { + rows: [ + { + node: { + entry: { + id: 'id1', + name: 'name1', + nodeType: 'st:site', + properties: { + 'cm:title': 'bogus' + } + } + } + } + ] + }, + row: { + node: { + entry: { + id: 'id2', + name: 'name1', + nodeType: 'st:site', + properties: { + 'cm:title': 'bogus' + } + } + } + } + }; + + component.context = context; + component.ngOnInit(); + + expect(component.displayText).toBe('bogus (name1)'); + }); +}); diff --git a/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.ts b/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.ts new file mode 100644 index 0000000000..f50bb97b2d --- /dev/null +++ b/lib/content-services/document-list/components/trashcan-name-column/trashcan-name-column.component.ts @@ -0,0 +1,87 @@ +/*! + * @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, + ChangeDetectionStrategy, + ViewEncapsulation, + OnInit, + Input +} from '@angular/core'; +import { MinimalNodeEntity } from 'alfresco-js-api'; +import { ShareDataRow } from '../../data/share-data-row.model'; + +@Component({ + selector: 'adf-trashcan-name-column', + template: ` + + {{ displayText }} + + + {{ displayText }} + + `, + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { class: 'adf-datatable-cell adf-trashcan-name-column' } +}) +export class TrashcanNameColumnComponent implements OnInit { + @Input() + context: any; + + isLibrary = false; + displayText: string; + displayTooltip: string; + node: MinimalNodeEntity; + + ngOnInit() { + this.node = this.context.row.node; + const rows: Array = this.context.data.rows || []; + + if (this.node && this.node.entry) { + this.isLibrary = this.node.entry.nodeType === 'st:site'; + + if (this.isLibrary) { + const { properties } = this.node.entry; + + this.displayText = this.makeLibraryTitle(this.node.entry, rows); + this.displayTooltip = + properties['cm:description'] || properties['cm:title']; + } else { + this.displayText = this.node.entry.name || this.node.entry.id; + } + } + } + + makeLibraryTitle(library: any, rows: Array): string { + const entries = rows.map((r: ShareDataRow) => r.node.entry); + const { id } = library; + const title = library.properties['cm:title']; + + let isDuplicate = false; + + if (entries) { + isDuplicate = entries.some((entry: any) => { + return entry.id !== id && entry.properties['cm:title'] === title; + }); + } + + return isDuplicate + ? `${library.properties['cm:title']} (${library.name})` + : `${library.properties['cm:title']}`; + } +} diff --git a/lib/content-services/document-list/document-list.module.ts b/lib/content-services/document-list/document-list.module.ts index 6e493fc5cb..72ab79d71d 100644 --- a/lib/content-services/document-list/document-list.module.ts +++ b/lib/content-services/document-list/document-list.module.ts @@ -31,6 +31,11 @@ import { DocumentListComponent } from './components/document-list.component'; import { EmptyFolderContentDirective } from './components/empty-folder/empty-folder-content.directive'; import { NoPermissionContentDirective } from './components/no-permission/no-permission-content.directive'; +import { TrashcanNameColumnComponent } from './components/trashcan-name-column/trashcan-name-column.component'; +import { LibraryStatusColumnComponent } from './components/library-status-column/library-status-column.component'; +import { LibraryRoleColumnComponent } from './components/library-role-column/library-role-column.component'; +import { LibraryNameColumnComponent } from './components/library-name-column/library-name-column.component'; +import { NameColumnComponent } from './components/name-column/name-column.component'; @NgModule({ imports: [ @@ -43,6 +48,11 @@ import { NoPermissionContentDirective } from './components/no-permission/no-perm declarations: [ DocumentListComponent, ContentColumnComponent, + TrashcanNameColumnComponent, + LibraryStatusColumnComponent, + LibraryRoleColumnComponent, + LibraryNameColumnComponent, + NameColumnComponent, ContentColumnListComponent, ContentActionComponent, ContentActionListComponent, @@ -52,6 +62,11 @@ import { NoPermissionContentDirective } from './components/no-permission/no-perm exports: [ DocumentListComponent, ContentColumnComponent, + TrashcanNameColumnComponent, + LibraryStatusColumnComponent, + LibraryRoleColumnComponent, + LibraryNameColumnComponent, + NameColumnComponent, ContentColumnListComponent, ContentActionComponent, ContentActionListComponent, diff --git a/lib/content-services/i18n/de.json b/lib/content-services/i18n/de.json index 77db718ace..728fc8e14e 100644 --- a/lib/content-services/i18n/de.json +++ b/lib/content-services/i18n/de.json @@ -299,6 +299,12 @@ "NAME": "Name" } }, + "ROLE": { + "MANAGER": "Manager", + "COLLABORATOR": "Mitarbeiter", + "CONTRIBUTOR": "Beitragender", + "CONSUMER": "Verbraucher" + }, "VISIBILITY": { "PRIVATE": "Privat", "PUBLIC": "Öffentlich", diff --git a/lib/content-services/i18n/en.json b/lib/content-services/i18n/en.json index 8cbc64424d..dfdf72289c 100644 --- a/lib/content-services/i18n/en.json +++ b/lib/content-services/i18n/en.json @@ -307,6 +307,12 @@ "VISIBILITY": "Visibility" } }, + "ROLE": { + "MANAGER": "Manager", + "COLLABORATOR": "Collaborator", + "CONTRIBUTOR": "Contributor", + "CONSUMER": "Consumer" + }, "VISIBILITY": { "PRIVATE": "Private", "PUBLIC": "Public", diff --git a/lib/content-services/i18n/es.json b/lib/content-services/i18n/es.json index 8167e57f3a..39f0b88cec 100644 --- a/lib/content-services/i18n/es.json +++ b/lib/content-services/i18n/es.json @@ -299,6 +299,12 @@ "NAME": "Nombre" } }, + "ROLE": { + "MANAGER": "Administrador", + "COLLABORATOR": "Colaborador", + "CONTRIBUTOR": "Contribuidor", + "CONSUMER": "Consumidor" + }, "VISIBILITY": { "PRIVATE": "Lista privada", "PUBLIC": "Público", diff --git a/lib/content-services/i18n/fr.json b/lib/content-services/i18n/fr.json index 8f010b0d08..9762136b1e 100644 --- a/lib/content-services/i18n/fr.json +++ b/lib/content-services/i18n/fr.json @@ -299,6 +299,12 @@ "NAME": "Nom" } }, + "ROLE": { + "MANAGER": "Gestionnaire", + "COLLABORATOR": "Collaborateur", + "CONTRIBUTOR": "Contributeur", + "CONSUMER": "Lecteur" + }, "VISIBILITY": { "PRIVATE": "Liste privée", "PUBLIC": "Public", diff --git a/lib/content-services/i18n/it.json b/lib/content-services/i18n/it.json index 1255969919..15a857f712 100644 --- a/lib/content-services/i18n/it.json +++ b/lib/content-services/i18n/it.json @@ -299,6 +299,12 @@ "NAME": "Nome" } }, + "ROLE": { + "MANAGER": "Manager", + "COLLABORATOR": "Collaboratore", + "CONTRIBUTOR": "Contributore", + "CONSUMER": "Consumatore" + }, "VISIBILITY": { "PRIVATE": "Privato", "PUBLIC": "Pubblico", diff --git a/lib/content-services/i18n/ja.json b/lib/content-services/i18n/ja.json index 3a7d3b5bae..5ed630f932 100644 --- a/lib/content-services/i18n/ja.json +++ b/lib/content-services/i18n/ja.json @@ -299,6 +299,12 @@ "NAME": "名前" } }, + "ROLE": { + "MANAGER": "マネージャ", + "COLLABORATOR": "共同作業者", + "CONTRIBUTOR": "投稿者", + "CONSUMER": "利用者" + }, "VISIBILITY": { "PRIVATE": "非公開", "PUBLIC": "公開", diff --git a/lib/content-services/i18n/nb.json b/lib/content-services/i18n/nb.json index 1b3ffee540..cf187f5bf5 100644 --- a/lib/content-services/i18n/nb.json +++ b/lib/content-services/i18n/nb.json @@ -299,6 +299,12 @@ "NAME": "Navn" } }, + "ROLE": { + "MANAGER": "Administrator", + "COLLABORATOR": "Medarbeider", + "CONTRIBUTOR": "Bidragsyter", + "CONSUMER": "Forbruker" + }, "VISIBILITY": { "PRIVATE": "Privat", "PUBLIC": "Offentlig", diff --git a/lib/content-services/i18n/nl.json b/lib/content-services/i18n/nl.json index c4beafb012..908ec68198 100644 --- a/lib/content-services/i18n/nl.json +++ b/lib/content-services/i18n/nl.json @@ -299,6 +299,12 @@ "NAME": "Naam" } }, + "ROLE": { + "MANAGER": "Beheerder", + "COLLABORATOR": "Medewerker", + "CONTRIBUTOR": "Bijdrager", + "CONSUMER": "Consument" + }, "VISIBILITY": { "PRIVATE": "Privé", "PUBLIC": "Openbaar", diff --git a/lib/content-services/i18n/pt-BR.json b/lib/content-services/i18n/pt-BR.json index 8a3e8e01cd..ae359aedbc 100644 --- a/lib/content-services/i18n/pt-BR.json +++ b/lib/content-services/i18n/pt-BR.json @@ -299,6 +299,12 @@ "NAME": "Nome" } }, + "ROLE": { + "MANAGER": "Gerente", + "COLLABORATOR": "Colaborador", + "CONTRIBUTOR": "Contribuidor", + "CONSUMER": "Consumidor" + }, "VISIBILITY": { "PRIVATE": "Privado", "PUBLIC": "Público", diff --git a/lib/content-services/i18n/ru.json b/lib/content-services/i18n/ru.json index 6f372ea2e8..1d9182d9e4 100644 --- a/lib/content-services/i18n/ru.json +++ b/lib/content-services/i18n/ru.json @@ -299,6 +299,12 @@ "NAME": "Имя" } }, + "ROLE": { + "MANAGER": "Менеджер", + "COLLABORATOR": "Редактор", + "CONTRIBUTOR": "Писатель", + "CONSUMER": "Читатель" + }, "VISIBILITY": { "PRIVATE": "Частный", "PUBLIC": "Общедоступный", diff --git a/lib/content-services/i18n/zh-CN.json b/lib/content-services/i18n/zh-CN.json index 65d13adbb3..0c1ee698e1 100644 --- a/lib/content-services/i18n/zh-CN.json +++ b/lib/content-services/i18n/zh-CN.json @@ -299,6 +299,12 @@ "NAME": "名称" } }, + "ROLE": { + "MANAGER": "管理员", + "COLLABORATOR": "合作者", + "CONTRIBUTOR": "贡献者", + "CONSUMER": "使用者" + }, "VISIBILITY": { "PRIVATE": "私有", "PUBLIC": "公共", diff --git a/lib/core/datatable/components/datatable/datatable.component.scss b/lib/core/datatable/components/datatable/datatable.component.scss index 0cfec9fe9c..ded0a5c307 100644 --- a/lib/core/datatable/components/datatable/datatable.component.scss +++ b/lib/core/datatable/components/datatable/datatable.component.scss @@ -177,6 +177,16 @@ border-collapse: unset; border-spacing: 0; + .adf-datatable-link { + text-decoration: none; + color: mat-color($foreground, text); + + &:hover { + color: #2196f3; + text-decoration: underline; + } + } + .adf-datatable-row { display: table-row; vertical-align: inherit; diff --git a/lib/extensions/src/lib/components/dynamic-column/dynamic-column.component.ts b/lib/extensions/src/lib/components/dynamic-column/dynamic-column.component.ts new file mode 100644 index 0000000000..adc372a3fe --- /dev/null +++ b/lib/extensions/src/lib/components/dynamic-column/dynamic-column.component.ts @@ -0,0 +1,100 @@ +/*! + * @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, + OnInit, + OnDestroy, + ViewChild, + ViewContainerRef, + ComponentRef, + ComponentFactoryResolver, + OnChanges, + SimpleChanges, + ViewEncapsulation, + ChangeDetectionStrategy +} from '@angular/core'; +import { ExtensionService } from '../../services/extension.service'; + +@Component({ + selector: 'adf-dynamic-column', + template: ` + + `, + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + host: { class: 'adf-dynamic-column' }, + styles: [ + ` + .adf-dynamic-column { + display: flex; + align-items: center; + } + ` + ] +}) +export class DynamicColumnComponent implements OnInit, OnChanges, OnDestroy { + @ViewChild('content', { read: ViewContainerRef }) + content: ViewContainerRef; + + @Input() + id: string; + + @Input() + context: any; + + private componentRef: ComponentRef; + + constructor( + private extensions: ExtensionService, + private componentFactoryResolver: ComponentFactoryResolver + ) {} + + ngOnInit() { + const componentType = this.extensions.getComponentById(this.id); + if (componentType) { + const factory = this.componentFactoryResolver.resolveComponentFactory( + componentType + ); + if (factory) { + this.content.clear(); + this.componentRef = this.content.createComponent(factory, 0); + this.updateInstance(); + } + } + } + + ngOnChanges(changes: SimpleChanges) { + if (changes.node) { + this.updateInstance(); + } + } + + ngOnDestroy() { + if (this.componentRef) { + this.componentRef.destroy(); + this.componentRef = null; + } + } + + private updateInstance() { + if (this.componentRef && this.componentRef.instance) { + this.componentRef.instance.context = this.context; + } + } +} diff --git a/lib/extensions/src/lib/extensions.module.ts b/lib/extensions/src/lib/extensions.module.ts index 537ec297fe..3a15f24f4f 100644 --- a/lib/extensions/src/lib/extensions.module.ts +++ b/lib/extensions/src/lib/extensions.module.ts @@ -18,9 +18,18 @@ import { NgModule } from '@angular/core'; import { DynamicExtensionComponent } from './components/dynamic-component/dynamic.component'; import { DynamicTabComponent } from './components/dynamic-tab/dynamic-tab.component'; +import { DynamicColumnComponent } from './components/dynamic-column/dynamic-column.component'; @NgModule({ - declarations: [DynamicExtensionComponent, DynamicTabComponent], - exports: [DynamicExtensionComponent, DynamicTabComponent] + declarations: [ + DynamicExtensionComponent, + DynamicTabComponent, + DynamicColumnComponent + ], + exports: [ + DynamicExtensionComponent, + DynamicTabComponent, + DynamicColumnComponent + ] }) export class ExtensionsModule {}