From f6c3fafe3245729311751b2f9af21ff711b30edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Popovics=20Andr=C3=A1s?= Date: Thu, 13 Jul 2017 15:49:21 +0100 Subject: [PATCH] [ADF-112] Change task details feature (due date) (#2071) * Add Assignee to readonly mode * Style adoption and first steps to editable mode * Switch between mode coverage * Rebase fix * Because of design and requirement changes, revert unnecessary parts * Small refactoring before the introduction of CardViewDateItem * Fix AdfCardView tests * Editable Card date item * Do not allow edit on task details after the task is completed. * Update task details request * Login footer switch fix * Login customisable copyright text * Card text item (first sketches) * Small fix for supported card items' template * Dynamic component loading for card view items * Test and linting fixes * Updating Readme.md * Update Readme.md * Fix Readme.md errors * CardViewTextItemComponent tests * Rebase fix --- .../login/login-demo.component.html | 5 +- .../components/login/login-demo.component.ts | 4 + .../config/webpack.common.js | 13 +- ng2-components/ng2-activiti-tasklist/index.ts | 2 + .../activiti-task-details.component.css | 2 +- .../activiti-task-details.component.ts | 36 +++- .../activiti-task-header.component.css | 15 -- .../activiti-task-header.component.html | 16 +- .../activiti-task-header.component.scss | 24 +++ .../activiti-task-header.component.spec.ts | 57 ++++- .../activiti-task-header.component.ts | 44 ++-- .../no-task-detail-template.component.spec.ts | 2 +- .../activiti-tasklist.service.spec.ts | 16 ++ .../src/services/activiti-tasklist.service.ts | 9 + ng2-components/ng2-alfresco-core/README.md | 198 ++++++++++++++++-- .../config/webpack.common.js | 13 +- .../docs/assets/adf-custom-view.png | Bin 58682 -> 75458 bytes ng2-components/ng2-alfresco-core/index.ts | 1 + .../adf-card-view-content-proxy.directive.ts | 25 +++ .../adf-card-view-dateitem.component.html | 23 ++ .../adf-card-view-dateitem.component.scss | 28 +++ .../adf-card-view-dateitem.component.spec.ts | 151 +++++++++++++ .../view/adf-card-view-dateitem.component.ts | 51 +++++ ...ard-view-item-dispatcher.component.spec.ts | 155 ++++++++++++++ ...adf-card-view-item-dispatcher.component.ts | 97 +++++++++ .../adf-card-view-textitem.component.html | 39 ++++ .../adf-card-view-textitem.component.scss | 80 +++++++ .../adf-card-view-textitem.component.spec.ts | 147 +++++++++++++ .../view/adf-card-view-textitem.component.ts | 65 ++++++ .../view/adf-card-view.component.css | 18 -- .../view/adf-card-view.component.html | 11 +- .../view/adf-card-view.component.scss | 32 +++ .../view/adf-card-view.component.spec.ts | 77 +++++-- .../view/adf-card-view.component.ts | 19 +- .../src/components/view/card-view.module.ts | 24 ++- .../src/interface/card-view-item.interface.ts | 26 +++ ...w.model.ts => card-view-baseitem.model.ts} | 20 +- .../src/models/card-view-dateitem.model.ts | 50 +++++ .../src/models/card-view-textitem.model.ts | 44 ++++ .../ng2-alfresco-core/src/models/index.ts | 3 +- .../services/adf-card-view-update.service.ts | 42 ++++ .../ng2-alfresco-core/src/services/index.ts | 1 + ng2-components/ng2-alfresco-login/README.md | 1 + .../config/webpack.common.js | 13 +- .../components/alfresco-login.component.html | 4 +- .../alfresco-login.component.spec.ts | 16 ++ .../components/alfresco-login.component.ts | 3 + 47 files changed, 1571 insertions(+), 151 deletions(-) delete mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.css create mode 100644 ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.scss create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-content-proxy.directive.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.html create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.scss create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.spec.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.spec.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.html create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.scss create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.spec.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.ts delete mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.css create mode 100644 ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.scss create mode 100644 ng2-components/ng2-alfresco-core/src/interface/card-view-item.interface.ts rename ng2-components/ng2-alfresco-core/src/models/{card-view.model.ts => card-view-baseitem.model.ts} (72%) create mode 100644 ng2-components/ng2-alfresco-core/src/models/card-view-dateitem.model.ts create mode 100644 ng2-components/ng2-alfresco-core/src/models/card-view-textitem.model.ts create mode 100644 ng2-components/ng2-alfresco-core/src/services/adf-card-view-update.service.ts diff --git a/demo-shell-ng2/app/components/login/login-demo.component.html b/demo-shell-ng2/app/components/login/login-demo.component.html index 4203567ec1..05c0f2bbcb 100644 --- a/demo-shell-ng2/app/components/login/login-demo.component.html +++ b/demo-shell-ng2/app/components/login/login-demo.component.html @@ -23,7 +23,7 @@

@@ -42,6 +42,7 @@ [disableCsrf]="disableCsrf" [showLoginActions]="showFooter" [showRememberMe]="showFooter" + copyrightText="© 2016 Alfresco Software, Inc. All Rights Reserved. (customised text)" (onSuccess)="onLogin($event)" (onError)="onError($event)">
@@ -67,7 +68,7 @@

diff --git a/demo-shell-ng2/app/components/login/login-demo.component.ts b/demo-shell-ng2/app/components/login/login-demo.component.ts index 010f7b83b6..9009b4982e 100644 --- a/demo-shell-ng2/app/components/login/login-demo.component.ts +++ b/demo-shell-ng2/app/components/login/login-demo.component.ts @@ -95,6 +95,10 @@ export class LoginDemoComponent implements OnInit { this.disableCsrf = !this.disableCsrf; } + toggleFooter() { + this.showFooter = !this.showFooter; + } + updateProvider() { if (this.isBPM && this.isECM) { this.providers = 'ALL'; diff --git a/ng2-components/ng2-activiti-tasklist/config/webpack.common.js b/ng2-components/ng2-activiti-tasklist/config/webpack.common.js index b872863854..7902fbfc1c 100644 --- a/ng2-components/ng2-activiti-tasklist/config/webpack.common.js +++ b/ng2-components/ng2-activiti-tasklist/config/webpack.common.js @@ -65,8 +65,17 @@ module.exports = { exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { - test: /\.component.scss$/, - use: ['to-string-loader', 'raw-loader', 'sass-loader'], + test: /\.scss$/, + use: [{ + loader: "to-string-loader" + }, { + loader: "raw-loader" + }, { + loader: "sass-loader", + options: { + includePaths: [ path.resolve(__dirname, '../../ng2-alfresco-core/styles')] + } + }], exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { diff --git a/ng2-components/ng2-activiti-tasklist/index.ts b/ng2-components/ng2-activiti-tasklist/index.ts index 345da37133..1f193854e7 100644 --- a/ng2-components/ng2-activiti-tasklist/index.ts +++ b/ng2-components/ng2-activiti-tasklist/index.ts @@ -20,6 +20,7 @@ import { ModuleWithProviders, NgModule } from '@angular/core'; import { MdAutocompleteModule, MdButtonModule, + MdCardModule, MdDatepickerModule, MdGridListModule, MdIconModule, @@ -91,6 +92,7 @@ export const ACTIVITI_TASKLIST_PROVIDERS: any[] = [ MdIconModule, MdButtonModule, MdInputModule, + MdCardModule, MdProgressSpinnerModule, MdDatepickerModule, MdNativeDateModule, diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.css b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.css index 6ed0c48abd..9ed5ae7394 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.css +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.css @@ -13,7 +13,7 @@ font-weight: 300; line-height: normal; overflow: hidden; - margin: 0; + margin: 0 0 8px 0; cursor: pointer; user-select: none; -moz-user-select: none; diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.ts index d3865518ab..83d4eeedc1 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-details.component.ts @@ -27,7 +27,7 @@ import { Component, ViewChild } from '@angular/core'; import { ContentLinkModel, FormModel, FormOutcomeEvent, FormService } from 'ng2-activiti-form'; -import { AlfrescoAuthenticationService, AlfrescoTranslationService, LogService } from 'ng2-alfresco-core'; +import { AlfrescoAuthenticationService, AlfrescoTranslationService, CardViewUpdateService, LogService, UpdateNotification } from 'ng2-alfresco-core'; import { TaskQueryRequestRepresentationModel } from '../models/filter.model'; import { TaskDetailsModel } from '../models/task-details.model'; import { User } from '../models/user.model'; @@ -39,7 +39,10 @@ declare let dialogPolyfill: any; @Component({ selector: 'adf-task-details, activiti-task-details', templateUrl: './activiti-task-details.component.html', - styleUrls: ['./activiti-task-details.component.css'] + styleUrls: ['./activiti-task-details.component.css'], + providers: [ + CardViewUpdateService + ] }) export class ActivitiTaskDetailsComponent implements OnInit, OnChanges { @@ -132,17 +135,20 @@ export class ActivitiTaskDetailsComponent implements OnInit, OnChanges { noTaskDetailsTemplateComponent: TemplateRef; /** - * Constructor - * @param auth Authentication service - * @param translate Translation service - * @param activitiForm Form service - * @param activitiTaskList Task service + * + * @param translateService + * @param activitiForm + * @param activitiTaskList + * @param logService + * @param authService */ constructor(private translateService: AlfrescoTranslationService, private activitiForm: FormService, private activitiTaskList: ActivitiTaskListService, private logService: LogService, - private authService: AlfrescoAuthenticationService) { + private authService: AlfrescoAuthenticationService, + private cardViewUpdateService: CardViewUpdateService +) { if (translateService) { translateService.addTranslationFolder('ng2-activiti-tasklist', 'assets/ng2-activiti-tasklist'); @@ -153,6 +159,8 @@ export class ActivitiTaskDetailsComponent implements OnInit, OnChanges { if (this.taskId) { this.loadDetails(this.taskId); } + + this.cardViewUpdateService.itemUpdated$.subscribe(this.updateTaskDetails.bind(this)); } ngOnChanges(changes: SimpleChanges): void { @@ -186,6 +194,18 @@ export class ActivitiTaskDetailsComponent implements OnInit, OnChanges { return this.taskDetails && this.taskDetails.duration === null; } + /** + * Save a task detail and update it after a successful response + * + * @param updateNotification + */ + private updateTaskDetails(updateNotification: UpdateNotification) { + this.activitiTaskList.updateTask(this.taskId, updateNotification.changed) + .subscribe( + () => { this.loadDetails(this.taskId); } + ); + } + /** * Load the activiti task details * @param taskId diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.css b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.css deleted file mode 100644 index 6b3b1c13f4..0000000000 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.css +++ /dev/null @@ -1,15 +0,0 @@ -:host { - width: 100%; -} - -.activiti-task-header__label { - font-weight: bold; -} - -.activiti-task-header__value { - color: rgb(68, 138, 255); -} - -.material-icons { - cursor: pointer; -} diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html index 8922608c4e..70033b0f08 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.html @@ -1,11 +1,13 @@ -
-
+ - + + + - + -
-
+ diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.scss b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.scss new file mode 100644 index 0000000000..488457f6ca --- /dev/null +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.scss @@ -0,0 +1,24 @@ +@import 'theming'; + +.#{$ADF} { + &-controls { + display: flex; + justify-content: space-between; + } + + &-edit-controls { + display: flex; + justify-content: flex-end; + margin-left: auto; + } + + &-switch-to-edit-mode, + &-save-edit-mode { + color: rgb(255, 152, 0); + } + + &-cancel-edit-mode, + &-claim-controls { + color: rgb(131, 131, 131); + } +} \ No newline at end of file diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts index e6ffa9cbdf..a7780a4e08 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.spec.ts @@ -15,9 +15,10 @@ * limitations under the License. */ +import { DebugElement } from '@angular/core'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; -import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core'; +import { AlfrescoTranslationService, CardViewUpdateService, CoreModule } from 'ng2-alfresco-core'; import { Observable } from 'rxjs/Rx'; import { TaskDetailsModel } from '../models/task-details.model'; @@ -31,6 +32,7 @@ describe('ActivitiTaskHeaderComponent', () => { let componentHandler: any; let component: ActivitiTaskHeaderComponent; let fixture: ComponentFixture; + let debugElement: DebugElement; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -41,7 +43,8 @@ describe('ActivitiTaskHeaderComponent', () => { ActivitiTaskHeaderComponent ], providers: [ - ActivitiTaskListService + ActivitiTaskListService, + CardViewUpdateService ] }).compileComponents(); @@ -54,6 +57,7 @@ describe('ActivitiTaskHeaderComponent', () => { fixture = TestBed.createComponent(ActivitiTaskHeaderComponent); component = fixture.componentInstance; service = TestBed.get(ActivitiTaskListService); + debugElement = fixture.debugElement; component.taskDetails = new TaskDetailsModel(taskDetailsMock); @@ -73,7 +77,7 @@ describe('ActivitiTaskHeaderComponent', () => { it('should display assignee', () => { component.ngOnChanges({}); fixture.detectChanges(); - let formNameEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .adf-header__value')); + let formNameEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .adf-property-value')); expect(formNameEl.nativeElement.innerText).toBe('Wilbur Adams'); }); @@ -81,10 +85,43 @@ describe('ActivitiTaskHeaderComponent', () => { component.taskDetails.assignee = null; component.ngOnChanges({}); fixture.detectChanges(); - let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .adf-header__value')); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-assignee"] .adf-property-value')); expect(valueEl.nativeElement.innerText).toBe('No assignee'); }); + it('should display created-by', () => { + component.ngOnChanges({}); + fixture.detectChanges(); + let formNameEl = fixture.debugElement.query(By.css('[data-automation-id="header-created-by"] .adf-property-value')); + expect(formNameEl.nativeElement.innerText).toBe('Wilbur Adams'); + }); + + it('should display placeholder if no created-by', () => { + component.taskDetails.assignee = null; + component.ngOnChanges({}); + fixture.detectChanges(); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-created-by"] .adf-property-value')); + expect(valueEl.nativeElement.innerText).toBe('No assignee'); + }); + + it('should set editable to false if the task has already completed', () => { + component.taskDetails.endDate = '05/05/2002'; + component.ngOnChanges({}); + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-dueDate"]`)); + expect(datePicker).toBeNull('Datepicker should NOT be in DOM'); + }); + + it('should set editable to true if the task has not completed yet', () => { + component.taskDetails.endDate = undefined; + component.ngOnChanges({}); + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-dueDate"]`)); + expect(datePicker).not.toBeNull('Datepicker should be in DOM'); + }); + it('should display the claim button if no assignee', () => { component.taskDetails.assignee = null; component.ngOnChanges({}); @@ -97,30 +134,30 @@ describe('ActivitiTaskHeaderComponent', () => { component.taskDetails.dueDate = '2016-11-03'; component.ngOnChanges({}); fixture.detectChanges(); - let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-header__value')); - expect(valueEl.nativeElement.innerText).toBe('Nov 03 2016'); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-property-value')); + expect(valueEl.nativeElement.innerText.trim()).toBe('Nov 03 2016'); }); it('should display placeholder if no due date', () => { component.taskDetails.dueDate = null; component.ngOnChanges({}); fixture.detectChanges(); - let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-header__value')); - expect(valueEl.nativeElement.innerText).toBe('No date'); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-dueDate"] .adf-property-value')); + expect(valueEl.nativeElement.innerText.trim()).toBe('No date'); }); it('should display form name', () => { component.formName = 'test form'; component.ngOnChanges({}); fixture.detectChanges(); - let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-formName"] .adf-header__value')); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-formName"] .adf-property-value')); expect(valueEl.nativeElement.innerText).toBe('test form'); }); it('should not display form name if no form name provided', () => { component.ngOnChanges({}); fixture.detectChanges(); - let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-formName"] .adf-header__value')); + let valueEl = fixture.debugElement.query(By.css('[data-automation-id="header-formName"] .adf-property-value')); expect(valueEl.nativeElement.innerText).toBe('No form'); }); diff --git a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts index e3415109a4..539326579c 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/activiti-task-header.component.ts @@ -16,14 +16,14 @@ */ import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core'; -import { AlfrescoTranslationService, CardViewModel, LogService } from 'ng2-alfresco-core'; +import { AlfrescoTranslationService, CardViewDateItemModel, CardViewItem, CardViewTextItemModel, LogService } from 'ng2-alfresco-core'; import { TaskDetailsModel } from '../models/index'; import { ActivitiTaskListService } from './../services/activiti-tasklist.service'; @Component({ selector: 'adf-task-header, activiti-task-header', templateUrl: './activiti-task-header.component.html', - styleUrls: ['./activiti-task-header.component.css'] + styleUrls: ['./activiti-task-header.component.scss'] }) export class ActivitiTaskHeaderComponent implements OnChanges { @@ -36,7 +36,8 @@ export class ActivitiTaskHeaderComponent implements OnChanges { @Output() claim: EventEmitter = new EventEmitter(); - properties: CardViewModel []; + properties: CardViewItem []; + inEdit: boolean = false; constructor(private translateService: AlfrescoTranslationService, private activitiTaskService: ActivitiTaskListService, @@ -47,6 +48,7 @@ export class ActivitiTaskHeaderComponent implements OnChanges { } ngOnChanges(changes: SimpleChanges) { + console.log('change van:', changes, this.taskDetails); this.refreshData(); } @@ -54,20 +56,22 @@ export class ActivitiTaskHeaderComponent implements OnChanges { if (this.taskDetails) { this.properties = [ - new CardViewModel({label: 'Status:', value: this.getTaskStatus(), key: 'status'}), - new CardViewModel({label: 'Due Date:', value: this.taskDetails.dueDate, format: 'MMM DD YYYY', key: 'dueDate', default: 'No date'}), - new CardViewModel({label: 'Category:', value: this.taskDetails.category, key: 'category', default: 'No category'}), - new CardViewModel( - { - label: 'Created By:', - value: this.taskDetails.getFullName(), - key: 'assignee', - default: 'No assignee' - }), - new CardViewModel({label: 'Created:', value: this.taskDetails.created, format: 'MMM DD YYYY', key: 'created'}), - new CardViewModel({label: 'Id:', value: this.taskDetails.id, key: 'id'}), - new CardViewModel({label: 'Description:', value: this.taskDetails.description, key: 'description', default: 'No description'}), - new CardViewModel({label: 'Form name:', value: this.formName, key: 'formName', default: 'No form'}) + new CardViewTextItemModel({ label: 'Assignee', value: this.taskDetails.getFullName(), key: 'assignee', default: 'No assignee' } ), + new CardViewTextItemModel({ label: 'Status', value: this.getTaskStatus(), key: 'status' }), + new CardViewDateItemModel({ label: 'Due Date', value: this.taskDetails.dueDate, key: 'dueDate', default: 'No date', editable: true }), + new CardViewTextItemModel({ label: 'Category', value: this.taskDetails.category, key: 'category', default: 'No category' }), + new CardViewTextItemModel({ label: 'Created By', value: this.taskDetails.getFullName(), key: 'created-by', default: 'No assignee' }), + new CardViewDateItemModel({ label: 'Created', value: this.taskDetails.created, key: 'created' }), + new CardViewTextItemModel({ label: 'Id', value: this.taskDetails.id, key: 'id' }), + new CardViewTextItemModel({ + label: 'Description', + value: this.taskDetails.description, + key: 'description', + default: 'No description', + multiline: true, + editable: true + }), + new CardViewTextItemModel({ label: 'Form name', value: this.formName, key: 'formName', default: 'No form' }) ]; } } @@ -81,7 +85,7 @@ export class ActivitiTaskHeaderComponent implements OnChanges { } getTaskStatus(): string { - return this.taskDetails.endDate ? 'Completed' : 'Running'; + return this.isCompleted() ? 'Completed' : 'Running'; } claimTask(taskId: string) { @@ -91,4 +95,8 @@ export class ActivitiTaskHeaderComponent implements OnChanges { this.claim.emit(taskId); }); } + + isCompleted() { + return !!this.taskDetails.endDate; + } } diff --git a/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts b/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts index f47f34faf9..a5e88d3eec 100644 --- a/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/components/no-task-detail-template.component.spec.ts @@ -24,7 +24,7 @@ describe('NoTaskDetailsTemplateDirective', () => { let detailsComponent: ActivitiTaskDetailsComponent; beforeEach(() => { - detailsComponent = new ActivitiTaskDetailsComponent(null, null, null, null, null); + detailsComponent = new ActivitiTaskDetailsComponent(null, null, null, null, null, null); component = new NoTaskDetailsTemplateDirective(detailsComponent); }); diff --git a/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.spec.ts b/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.spec.ts index 0ebaa7e91a..a5913a5d73 100644 --- a/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.spec.ts +++ b/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.spec.ts @@ -562,6 +562,22 @@ describe('Activiti TaskList Service', () => { }); }); + it('should update a task', (done) => { + let taskId = '111'; + + service.updateTask(taskId, {property: 'value'}).subscribe( + (res: any) => { + done(); + } + ); + + jasmine.Ajax.requests.mostRecent().respondWith({ + 'status': 200, + contentType: 'application/json', + responseText: JSON.stringify({}) + }); + }); + it('should return the filter if it contains task id', (done) => { let taskId = '1'; let filterFake = new FilterRepresentationModel({ diff --git a/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.ts b/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.ts index 61b9adec5c..5000d9a8a3 100644 --- a/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.ts +++ b/ng2-components/ng2-activiti-tasklist/src/services/activiti-tasklist.service.ts @@ -375,6 +375,15 @@ export class ActivitiTaskListService { .catch(err => this.handleError(err)); } + /** + * Update due date + * @param dueDate - the new due date + */ + updateTask(taskId: any, updated): Observable { + return Observable.fromPromise(this.apiService.getInstance().activiti.taskApi.updateTask(taskId, updated)) + .catch(err => this.handleError(err)); + } + private callApiTasksFiltered(requestNode: TaskQueryRequestRepresentationModel) { return this.apiService.getInstance().activiti.taskApi.listTasks(requestNode); } diff --git a/ng2-components/ng2-alfresco-core/README.md b/ng2-components/ng2-alfresco-core/README.md index 1ac570ba82..6d666b238b 100644 --- a/ng2-components/ng2-alfresco-core/README.md +++ b/ng2-components/ng2-alfresco-core/README.md @@ -29,7 +29,16 @@ * [Events](#events-1) - [ADF Card View](#adf-card-view) * [Properties](#properties-2) - * [CardViewModel](#cardviewmodel) + * [Editing](#editing) + * [Defining properties](#defining-properties) + * [Card Text Item](#card-text-item) + + [Options](#options) + * [Card Date Item](#card-date-item) + + [Options](#options-1) + * [Defining your custom card Item](#defining-your-custom-card-item) + + [1. Define the model for the custom type](#1-define-the-model-for-the-custom-type) + + [2. Define the component for the custom type](#2-define-the-component-for-the-custom-type) + + [3. Add you custom component to your module's entryComponents list](#3-add-you-custom-component-to-your-modules-entrycomponents-list) - [AlfrescoTranslationService](#alfrescotranslationservice) - [Renditions Service](#renditions-service) - [Build from sources](#build-from-sources) @@ -593,40 +602,193 @@ export class AppComponent { ## ADF Card View -The component shows the [CardViewModel](#cardviewmodel)} object. +The CardViewComponent is a configurable property list renderer. You define the property list, the CardViewComponent does the rest. Each property represents a card view item (a row) in the card view component. At the time of writing two different kind of card view item (property type) is supported out of the box ([text](#card-text-item) item and [date](#card-date-item) item) but you can define your own custom types as well. ```html + [properties]="[{label: 'My Label', value: 'My value'}]" + [editable]="false"> ``` +![adf-custom-view](docs/assets/adf-custom-view.png) + ### Properties | Name | Type | Description | | --- | --- | --- | -| properties | {array[CardViewModel](#cardviewmodel)} | (**required**) The custom view to render | +| properties | [CardViewItem](#cardviewitem)[] | (**required**) The custom view to render | +| editable | boolean | If the component editable or not | -### CardViewModel +### Editing -```json -{ - "label": "string", - "value": "any", - "format": "string", - "default": "string" +The card view can optionally allow its properties to be edited. You can control the editing of the properties in two level. +- **global level** - *via the editable paramter of the adf-card-view component* +- **property level** - *in each property via the editable attribute* + +If you set the global editable parameter to false, no properties can be edited regardless of what is set inside the property. + +### Defining properties + +Properties is an array of models which one by one implements the CardViewItem interface. + +```js +export interface CardViewItem { + label: string; + value: any; + key: string; + default?: any; + type: string; + displayValue: string; + editable?: boolean; } ``` -| Name | Type | Description | -| --- | --- | --- | -| label | string | The label to render | -| value | string | The value to render | -| format | string | The format to use in case the value is a date | -| default | string | The default value to render in case the value is empty | +At the moment two models are defined out of the box: -![adf-custom-view](docs/assets/adf-custom-view.png) +- **[CardViewTextItemModel](#card-text-item)** - *for text items* +- **[CardViewDateItemModel](#card-date-item)** - *for date items* + +Each of them are extending the abstract CardViewBaseItemModel class, and each of them are adding some custom functionality to the basic behaviour. + +```js + this.properties = [ + new CardViewTextItemModel({ + label: 'Name', + value: 'Spock', + key: 'name', + default: 'default bar' , + multiline: false + }), + new CardViewDateItemModel({ + label: 'Birth of date', + value: someDate, + key: 'birth-of-date', + default: new Date(), + format: '', + editable: true + }), + ... +] +``` + +### Card Text Item + +CardViewTextItemModel is a property type for text properties. + +```js +const textItemProperty = new CardViewTextItemModel(options); +``` + +#### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| label* | string | --- | The label to render | +| value* | any | --- | The original value | +| key* | string | --- | the key of the property. Have an important role when editing the property. | +| default | any | --- | The default value to render in case the value is empty | +| displayValue* | string | --- | The value to render | +| editable | boolean | false | Whether the property editable or not | +| multiline | string | false | Single or multiline text | + +### Card Date Item + +CardViewDateItemModel is a property type for date properties. + +```js +const dateItemProperty = new CardViewDateItemModel(options); +``` + +#### Options + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| label* | string | --- | The label to render | +| value* | any | --- | The original value | +| key* | string | --- | the key of the property. Have an important role when editing the property. | +| default | any | --- | The default value to render in case the value is empty | +| displayValue* | string | --- | The value to render | +| editable | boolean | false | Whether the property editable or not | +| format | boolean | "MMM DD YYYY" | any format that momentjs accepts | + +### Defining your custom card Item + +Card item components are loaded dynamically, which makes you able to define your own custom component for the custom card item type. + +Let's consider you want to have a **stardate** type to display Captain Picard's birthday (47457.1). For this, you need to do the following steps. + +#### 1. Define the model for the custom type + +Your model has to extend the CardViewBaseItemModel and implement the CardViewItem interface. +*(You can check how the CardViewTextItemModel is implemented for further guidance.)* + +```js +export class CardViewStarDateItemModel extends CardViewBaseItemModel implements CardViewItem { + type: string = 'star-date'; + + get displayValue() { + return this.convertToStarDate(this.value) || this.default; + } + + private convertToStarDate(starTimeStamp: number): string { + // Do the magic + } +} +``` + +The most important part of this model is the value of the **type** attribute. This is how the Card View component will be able to recognise which component is needed to render it dynamically. + +The type is a **hyphen-separated-lowercase-words** string (just like how I wrote it). This will be converted to a PascalCase (or UpperCamelCase) string to find the right component. In our case the Card View component will look for the CardView**StarDate**ItemComponent. + +#### 2. Define the component for the custom type + +As discussed in the previous step the only important thing here is the naming of your component class ( **CardViewStarDateItemComponent**). Since the selector is not used in this case, you can give any selector name to it, but it make sense to follow the angular standards. + +```js +@Component({ + selector: 'card-view-stardateitem' // For example + ... +}) +export class CardViewStarDateItemComponent { + @Input() + property: CardViewStarDateItemModel; + + @Input() + editable: boolean; + + constructor(private cardViewUpdateService: CardViewUpdateService) {} + + isEditble() { + return this.editable && this.property.editable; + } + + showStarDatePicker() { + ... + } +} + +``` +To make your component editable, you can have a look on either the CardViewTextItemComponent' or on the CardViewDateItemComponent's source. + +#### 3. Add you custom component to your module's entryComponents list + +For Angular to be able to load your custom component dynamically, you have to register your component in your modules entryComponents. + +```js +@NgModule({ + imports: [...], + declarations: [ + CardViewStarDateItemComponent + ], + entryComponents: [ + CardViewStarDateItemComponent + ], + exports: [...] +}) +export class MyModule {} +``` ## AlfrescoTranslationService diff --git a/ng2-components/ng2-alfresco-core/config/webpack.common.js b/ng2-components/ng2-alfresco-core/config/webpack.common.js index 5c1dc42fe3..c4f1184dd6 100644 --- a/ng2-components/ng2-alfresco-core/config/webpack.common.js +++ b/ng2-components/ng2-alfresco-core/config/webpack.common.js @@ -60,8 +60,17 @@ module.exports = { exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { - test: /\.component.scss$/, - use: ['to-string-loader', 'raw-loader', 'sass-loader'], + test: /\.scss$/, + use: [{ + loader: "to-string-loader" + }, { + loader: "raw-loader" + }, { + loader: "sass-loader", + options: { + includePaths: [ path.resolve(__dirname, '../styles')] + } + }], exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { diff --git a/ng2-components/ng2-alfresco-core/docs/assets/adf-custom-view.png b/ng2-components/ng2-alfresco-core/docs/assets/adf-custom-view.png index 41ed32afb9f5642a1e3a4cedf04494954f8842a6..4b99842c33f4c8183c9ae326633cdc65ca3421c2 100644 GIT binary patch literal 75458 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
    MDXCggl_^~9Z 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

    E9`hN*fEA5x57C_6}aIDE&{q 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 P__?R1eYf}yH2D7jh!l?R literal 58682 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

    BY|ZJVK~|DSfcVI790KYt{0_eC#FUW*fr7fW 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 Uvo!70J~9A-r>mdKI;Vst0Mm$d3jhEB diff --git a/ng2-components/ng2-alfresco-core/index.ts b/ng2-components/ng2-alfresco-core/index.ts index d6cd96016a..d185691199 100644 --- a/ng2-components/ng2-alfresco-core/index.ts +++ b/ng2-components/ng2-alfresco-core/index.ts @@ -69,6 +69,7 @@ export { ContextMenuModule } from './src/components/context-menu/context-menu.mo export { CardViewModule } from './src/components/view/card-view.module'; export { CollapsableModule } from './src/components/collapsable/collapsable.module'; export { UserPreferencesService } from './src/services/user-preferences.service'; +export { CardViewItem } from './src/interface/card-view-item.interface'; export * from './src/services/index'; export * from './src/components/data-column/data-column.component'; export * from './src/components/data-column/data-column-list.component'; diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-content-proxy.directive.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-content-proxy.directive.ts new file mode 100644 index 0000000000..00e65a40f7 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-content-proxy.directive.ts @@ -0,0 +1,25 @@ +/*! + * @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 { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[adf-card-view-content-proxy]' +}) +export class AdfCardViewContentProxyDirective { + constructor(public viewContainerRef: ViewContainerRef) { } +} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.html b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.html new file mode 100644 index 0000000000..896ff9a5aa --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.html @@ -0,0 +1,23 @@ +

    {{ property.label }}
    +
    + + {{ property.displayValue }} + + + {{ property.displayValue }} + + + + + +
    diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.scss b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.scss new file mode 100644 index 0000000000..f10e76ee69 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.scss @@ -0,0 +1,28 @@ +@import 'theming'; + +.#{$ADF} { + &-invisible-date-input { + height: 24px; + width: 0; + overflow: hidden; + opacity: 0; + border: none; + margin: 0; + padding: 0; + } + + &-dateitem-editable { + cursor: pointer; + + button { + width: 16px; + height: 16px; + opacity: 0.5; + margin-left: 4px; + } + + &:hover button { + opacity: 1; + } + } +} \ No newline at end of file diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.spec.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.spec.ts new file mode 100644 index 0000000000..f491f7a9f8 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.spec.ts @@ -0,0 +1,151 @@ +/*! + * @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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { MdDatepickerModule, MdInputModule, MdNativeDateModule } from '@angular/material'; +import { By } from '@angular/platform-browser'; +import { CardViewDateItemModel } from '../../models/card-view-dateitem.model'; +import { CardViewUpdateService } from '../../services/adf-card-view-update.service'; +import { CardViewDateItemComponent } from './adf-card-view-dateitem.component'; + +describe('CardViewDateItemComponent', () => { + + let fixture: ComponentFixture; + let component: CardViewDateItemComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + MdDatepickerModule, + MdInputModule, + MdNativeDateModule + ], + declarations: [ + CardViewDateItemComponent + ], + providers: [ + CardViewUpdateService + ] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CardViewDateItemComponent); + component = fixture.componentInstance; + component.property = { + type: 'date', + label: 'Date label', + value: new Date('07/10/2017'), + key: 'datekey', + default: '', + format: '', + editable: false, + get displayValue(): string { + return 'Jul 10 2017'; + } + }; + }); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should render the label and value', () => { + fixture.detectChanges(); + + let labelValue = fixture.debugElement.query(By.css('.adf-property-label')); + expect(labelValue).not.toBeNull(); + expect(labelValue.nativeElement.innerText).toBe('Date label'); + + let value = fixture.debugElement.query(By.css('.adf-property-value')); + expect(value).not.toBeNull(); + expect(value.nativeElement.innerText.trim()).toBe('Jul 10 2017'); + }); + + it('should render value when editable:true', () => { + component.editable = true; + component.property.editable = true; + fixture.detectChanges(); + + let value = fixture.debugElement.query(By.css('.adf-property-value')); + expect(value).not.toBeNull(); + expect(value.nativeElement.innerText.trim()).toBe('Jul 10 2017'); + }); + + it('should render the picker and toggle in case of editable:true', () => { + component.editable = true; + component.property.editable = true; + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`)); + let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`)); + expect(datePicker).not.toBeNull('Datepicker should be in DOM'); + expect(datePickerToggle).not.toBeNull('Datepicker toggle should be shown'); + }); + + it('should NOT render the picker and toggle in case of editable:false', () => { + component.property.editable = false; + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`)); + let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`)); + expect(datePicker).toBeNull('Datepicker should NOT be in DOM'); + expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown'); + }); + + it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', () => { + component.editable = false; + component.property.editable = true; + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`)); + let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`)); + expect(datePicker).toBeNull('Datepicker should NOT be in DOM'); + expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown'); + }); + + it('should open the datetimepicker when clicking on the label', () => { + component.editable = true; + component.property.editable = true; + fixture.detectChanges(); + spyOn(component.datepicker, 'open'); + + let datePickerLabelToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-label-toggle-${component.property.key}"]`)); + datePickerLabelToggle.triggerEventHandler('click', {}); + + expect(component.datepicker.open).toHaveBeenCalled(); + }); + + it('should trigger an update event on the CardViewUpdateService', (done) => { + component.editable = true; + component.property.editable = true; + const cardViewUpdateService = TestBed.get(CardViewUpdateService); + const expectedDate = new Date('11/11/2017'); + fixture.detectChanges(); + + cardViewUpdateService.itemUpdated$.subscribe( + (updateNotification) => { + expect(updateNotification.target).toBe(component.property); + expect(updateNotification.changed).toEqual({ datekey: expectedDate }); + done(); + } + ); + + component.datepicker.selectedChanged.next(expectedDate); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.ts new file mode 100644 index 0000000000..40f4822bc9 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-dateitem.component.ts @@ -0,0 +1,51 @@ +/*! + * @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, ViewChild } from '@angular/core'; +import { MdDatepicker } from '@angular/material'; +import { CardViewDateItemModel } from '../../models/card-view-dateitem.model'; +import { CardViewUpdateService } from '../../services/adf-card-view-update.service'; + +@Component({ + selector: 'adf-card-view-dateitem', + templateUrl: './adf-card-view-dateitem.component.html', + styleUrls: ['./adf-card-view-dateitem.component.scss'] +}) +export class CardViewDateItemComponent { + @Input() + property: CardViewDateItemModel; + + @Input() + editable: boolean; + + @ViewChild(MdDatepicker) + public datepicker: MdDatepicker; + + constructor(private cardViewUpdateService: CardViewUpdateService) {} + + isEditble() { + return this.editable && this.property.editable; + } + + showDatePicker() { + this.datepicker.open(); + } + + dateChanged(changed) { + this.cardViewUpdateService.update(this.property, { [this.property.key]: changed }); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.spec.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.spec.ts new file mode 100644 index 0000000000..b0e598a3cc --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.spec.ts @@ -0,0 +1,155 @@ +/*! + * @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 } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; +import { CardViewItem } from '../../interface/card-view-item.interface'; +import { AdfCardViewContentProxyDirective } from './adf-card-view-content-proxy.directive'; +import { CardViewItemDispatcherComponent } from './adf-card-view-item-dispatcher.component'; + +@Component({ + selector: 'whatever-you-want-to-have', + template: '
    Hey I am shiny!
    ' +}) +export class CardViewShinyCustomElementItemComponent { + @Input() property: CardViewItem; + @Input() editable: boolean; +} + +describe('CardViewItemDispatcherComponent', () => { + + let fixture: ComponentFixture; + let component: CardViewItemDispatcherComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [], + declarations: [ + CardViewItemDispatcherComponent, + CardViewShinyCustomElementItemComponent, + AdfCardViewContentProxyDirective + ], + providers: [] + }); + + // entryComponents are not supported yet on TestBed, that is why this ugly workaround: + // https://github.com/angular/angular/issues/10760 + TestBed.overrideModule(BrowserDynamicTestingModule, { + set: { entryComponents: [ CardViewShinyCustomElementItemComponent ] } + }); + + TestBed.compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CardViewItemDispatcherComponent); + component = fixture.componentInstance; + component.property = { + type: 'shiny-custom-element', + label: 'Shiny custom element', + value: null, + key: 'customkey', + default: '', + editable: false, + get displayValue(): string { + return 'custom value displayed'; + } + }; + component.editable = true; + + fixture.detectChanges(); + component.ngOnChanges(null); + }); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + describe('Subcompomnent creation', () => { + + it('should load the CardViewShinyCustomElementItemComponent', () => { + const innerElement = fixture.debugElement.query(By.css('[data-automation-id="found-me"]')); + expect(innerElement).not.toBeNull(); + }); + + it('should load the CardViewShinyCustomElementItemComponent only ONCE', () => { + component.ngOnChanges(); + component.ngOnChanges(); + component.ngOnChanges(); + fixture.detectChanges(); + + const shinyCustomElementItemComponent = fixture.debugElement.queryAll(By.css('whatever-you-want-to-have')); + + expect(shinyCustomElementItemComponent.length).toEqual(1); + }); + + it('should pass through the property and editable parameters', () => { + const shinyCustomElementItemComponent = fixture.debugElement.query(By.css('whatever-you-want-to-have')).componentInstance; + + expect(shinyCustomElementItemComponent.property).toBe(component.property); + expect(shinyCustomElementItemComponent.editable).toBe(component.editable); + }); + }); + + describe('Angular lifecycle methods', () => { + + let shinyCustomElementItemComponent; + + const lifeCycleMethods = [ + 'ngOnChanges', + 'ngOnInit', + 'ngDoCheck', + 'ngAfterContentInit', + 'ngAfterContentChecked', + 'ngAfterViewInit', + 'ngAfterViewChecked', + 'ngOnDestroy' + ]; + + beforeEach(() => { + shinyCustomElementItemComponent = fixture.debugElement.query(By.css('whatever-you-want-to-have')).componentInstance; + }); + + it('should call through the lifecycle methods', () => { + lifeCycleMethods.forEach((lifeCycleMethod) => { + shinyCustomElementItemComponent[lifeCycleMethod] = () => {}; + spyOn(shinyCustomElementItemComponent, lifeCycleMethod); + const param1 = {}; + const param2 = {}; + + component[lifeCycleMethod].call(component, param1, param2); + + expect(shinyCustomElementItemComponent[lifeCycleMethod]).toHaveBeenCalledWith(param1, param2); + }); + }); + + it('should NOT call through the lifecycle methods if the method does not exist (no error should be thrown)', () => { + lifeCycleMethods.forEach((lifeCycleMethod) => { + shinyCustomElementItemComponent[lifeCycleMethod] = undefined; + + const execution = () => { + component[lifeCycleMethod].call(component); + }; + + expect(execution).not.toThrowError(); + }); + }); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.ts new file mode 100644 index 0000000000..2028708fdf --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-item-dispatcher.component.ts @@ -0,0 +1,97 @@ +/*! + * @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, + ComponentFactoryResolver, + Input, + OnChanges, + Type, + ViewChild +} from '@angular/core'; +import { CardViewItem } from '../../interface/card-view-item.interface'; +import { AdfCardViewContentProxyDirective } from './adf-card-view-content-proxy.directive'; + +@Component({ + selector: 'adf-card-view-item-dispatcher', + template: '' +}) +export class CardViewItemDispatcherComponent implements OnChanges { + @Input() + property: CardViewItem; + + @Input() + editable: boolean; + + @ViewChild(AdfCardViewContentProxyDirective) + private content: AdfCardViewContentProxyDirective; + + private loaded: boolean = false; + private componentReference: any = null; + + public ngOnInit; + public ngDoCheck; + + constructor(private resolver: ComponentFactoryResolver) { + const dynamicLifecycleMethods = [ + 'ngOnInit', + 'ngDoCheck', + 'ngAfterContentInit', + 'ngAfterContentChecked', + 'ngAfterViewInit', + 'ngAfterViewChecked', + 'ngOnDestroy' + ]; + + dynamicLifecycleMethods.forEach((dynamicLifecycleMethod) => { + this[dynamicLifecycleMethod] = this.proxy.bind(this, dynamicLifecycleMethod); + }); + } + + ngOnChanges(...args) { + if (!this.loaded) { + this.loadComponent(); + this.loaded = true; + } + + this.proxy('ngOnChanges', ...args); + } + + private loadComponent() { + const upperCamelCasedType = this.getUpperCamelCase(this.property.type), + className = `CardView${upperCamelCasedType}ItemComponent`; + + const factories = Array.from(this.resolver['_factories'].keys()); + const factoryClass = >factories.find((x: any) => x.name === className); + const factory = this.resolver.resolveComponentFactory(factoryClass); + this.componentReference = this.content.viewContainerRef.createComponent(factory); + + this.componentReference.instance.editable = this.editable; + this.componentReference.instance.property = this.property; + } + + private getUpperCamelCase(type: string): string { + const camelCasedType = type.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); + return camelCasedType[0].toUpperCase() + camelCasedType.substr(1); + } + + private proxy(methodName, ...args) { + if (this.componentReference.instance[methodName]) { + this.componentReference.instance[methodName].apply(this.componentReference.instance, args); + } + } +} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.html b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.html new file mode 100644 index 0000000000..db42631255 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.html @@ -0,0 +1,39 @@ +
    {{ property.label }}
    +
    + + {{ property.displayValue }} + + +
    + {{ property.displayValue }} + create +
    +
    + + + + + done + clear +
    +
    +
    \ No newline at end of file diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.scss b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.scss new file mode 100644 index 0000000000..e9111148dc --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.scss @@ -0,0 +1,80 @@ +@import 'theming'; + +.#{$ADF} { + &-textitem-icon { + font-size: 16px; + width: 16px; + height: 16px; + position: relative; + top: 3px; + padding-left: 8px; + opacity: 0.5; + } + + &-update-icon { + padding-left: 13px; + } + + &-textitem-readonly { + cursor: pointer; + + &:hover md-icon { + opacity: 1; + } + } + + &-textitem-editable { + display: flex; + + md-icon:hover { + opacity: 1; + cursor: pointer; + } + + md-input-container { + width: 100%; + } + + input:focus, + textarea:focus { + border: 1px solid #EEE; + } + } + + &-textitem-editable /deep/ .mat-input-wrapper { + margin: 0; + padding-bottom: 0; + } + + &-textitem-editable /deep/ .mat-input-underline { + display: none; + } + + &-textitem-editable /deep/ .mat-input-placeholder-wrapper { + padding-top: 2em; + } + + &-textitem-editable /deep/ .mat-input-placeholder { + top: 3px; + } + + &-textitem-editable /deep/ .mat-input-element { + font-family: inherit; + position: relative; + padding-top: 3px; + } + + &-textitem-editable /deep/ .mat-input-element:focus { + padding: 5px; + left: -6px; + top: -3px; + } + + &-textitem-editable /deep/ input.mat-input-element { + margin-bottom: 2px; + } + + &-textitem-editable /deep/ input.mat-input-element:focus { + margin-bottom: -7px; + } +} \ No newline at end of file diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.spec.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.spec.ts new file mode 100644 index 0000000000..621d5ff77d --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.spec.ts @@ -0,0 +1,147 @@ +/*! + * @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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; +import { MdDatepickerModule, MdIconModule, MdInputModule, MdNativeDateModule } from '@angular/material'; +import { By } from '@angular/platform-browser'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { CardViewTextItemModel } from '../../models/card-view-textitem.model'; +import { CardViewUpdateService } from '../../services/adf-card-view-update.service'; +import { CardViewTextItemComponent } from './adf-card-view-textitem.component'; + +describe('CardViewTextItemComponent', () => { + + let fixture: ComponentFixture; + let component: CardViewTextItemComponent; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + FormsModule, + NoopAnimationsModule, + MdDatepickerModule, + MdIconModule, + MdInputModule, + MdNativeDateModule + ], + declarations: [ + CardViewTextItemComponent + ], + providers: [ + CardViewUpdateService + ] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(CardViewTextItemComponent); + component = fixture.componentInstance; + component.property = { + type: 'text', + label: 'Text label', + value: 'Lorem ipsum', + key: 'textkey', + default: '', + editable: false, + get displayValue(): string { + return 'Lorem ipsum'; + } + }; + }); + + afterEach(() => { + fixture.destroy(); + TestBed.resetTestingModule(); + }); + + it('should render the label and value', () => { + fixture.detectChanges(); + + let labelValue = fixture.debugElement.query(By.css('.adf-property-label')); + expect(labelValue).not.toBeNull(); + expect(labelValue.nativeElement.innerText).toBe('Text label'); + + let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`)); + expect(value).not.toBeNull(); + expect(value.nativeElement.innerText.trim()).toBe('Lorem ipsum'); + }); + + it('should render value when editable:true', () => { + component.editable = true; + component.property.editable = true; + fixture.detectChanges(); + + let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`)); + expect(value).not.toBeNull(); + expect(value.nativeElement.innerText.trim()).toBe('Lorem ipsum'); + }); + + it('should render the edit icon in case of editable:true', () => { + component.editable = true; + component.property.editable = true; + fixture.detectChanges(); + + let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`)); + expect(editIcon).not.toBeNull('Edit icon should be shown'); + }); + + it('should NOT render the edit icon in case of editable:false', () => { + component.editable = false; + fixture.detectChanges(); + + let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`)); + expect(editIcon).toBeNull('Edit icon should NOT be shown'); + }); + + it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', () => { + component.editable = false; + component.property.editable = true; + fixture.detectChanges(); + + let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`)); + expect(editIcon).toBeNull('Edit icon should NOT be shown'); + }); + + it('should trigger an update event on the CardViewUpdateService', (done) => { + component.editable = true; + component.property.editable = true; + const cardViewUpdateService = TestBed.get(CardViewUpdateService); + const expectedText = 'changed text'; + fixture.detectChanges(); + + cardViewUpdateService.itemUpdated$.subscribe( + (updateNotification) => { + expect(updateNotification.target).toBe(component.property); + expect(updateNotification.changed).toEqual({ textkey: expectedText }); + done(); + } + ); + + let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-toggle-${component.property.key}"]`)); + editIcon.triggerEventHandler('click', null); + fixture.detectChanges(); + + let editInput = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-editinput-${component.property.key}"]`)); + editInput.nativeElement.value = expectedText; + editInput.nativeElement.dispatchEvent(new Event('input')); + fixture.detectChanges(); + + let updateInput = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-update-${component.property.key}"]`)); + updateInput.triggerEventHandler('click', null); + }); +}); diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.component.ts new file mode 100644 index 0000000000..55fb177469 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view-textitem.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, OnChanges, ViewChild } from '@angular/core'; +import { CardViewTextItemModel } from '../../models/card-view-textitem.model'; +import { CardViewUpdateService } from '../../services/adf-card-view-update.service'; + +@Component({ + selector: 'adf-card-view-textitem', + templateUrl: './adf-card-view-textitem.component.html', + styleUrls: ['./adf-card-view-textitem.component.scss'] +}) +export class CardViewTextItemComponent implements OnChanges { + @Input() + property: CardViewTextItemModel; + + @Input() + editable: boolean; + + @ViewChild('editorInput') + private editorInput: any; + + inEdit: boolean = false; + editedValue: string; + + constructor(private cardViewUpdateService: CardViewUpdateService) {} + + ngOnChanges() { + this.editedValue = this.property.value; + } + + isEditble() { + return this.editable && this.property.editable; + } + + setEditMode(editStatus: boolean): void { + this.inEdit = editStatus; + setTimeout(() => { + this.editorInput.nativeElement.click(); + }, 0); + } + + reset(): void { + this.editedValue = this.property.value; + this.setEditMode(false); + } + + update(): void { + this.cardViewUpdateService.update(this.property, { [this.property.key]: this.editedValue }); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.css b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.css deleted file mode 100644 index 1e122ae577..0000000000 --- a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.css +++ /dev/null @@ -1,18 +0,0 @@ -:host { - width: 100%; -} - -.adf-header__label { - font-weight: bold; - float: left; - width: 50%; - word-wrap: break-word; -} - -.adf-header__value { - color: rgb(68, 138, 255); -} - -.material-icons { - cursor: pointer; -} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.html b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.html index 891a7b2ff0..b74f8d0d1c 100644 --- a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.html +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.html @@ -1,6 +1,7 @@ -
    -
    -
    {{ property.label }}
    -
    {{ getPropertyValue(property) }}
    -
    +
    + +
    + +
    +
    diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.scss b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.scss new file mode 100644 index 0000000000..d4e693ef24 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.scss @@ -0,0 +1,32 @@ +@import 'theming'; + +.#{$ADF} { + &-property-list { + display: table; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + } + + &-property { + display: table-row; + } + + &-property /deep/ &-property-label { + display: table-cell; + min-width: 100px; + padding-right: 30px; + word-wrap: break-word; + color: rgb(186, 186, 186); + vertical-align: top; + padding-bottom: 20px; + } + + &-property /deep/ &-property-value { + width: 100%; + display: table-cell; + color: rgb(101, 101, 101); + vertical-align: top; + padding-bottom: 20px; + } +} diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.spec.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.spec.ts index 0a882630f2..1bb1d6e5e0 100644 --- a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.spec.ts +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.spec.ts @@ -16,8 +16,17 @@ */ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormsModule } from '@angular/forms'; +import { MdDatepickerModule, MdIconModule, MdInputModule, MdNativeDateModule } from '@angular/material'; import { By } from '@angular/platform-browser'; -import { CardViewModel } from '../../models/card-view.model'; +import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing'; +import { CardViewDateItemModel } from '../../models/card-view-dateitem.model'; +import { CardViewTextItemModel } from '../../models/card-view-textitem.model'; +import { CardViewUpdateService } from '../../services/adf-card-view-update.service'; +import { AdfCardViewContentProxyDirective } from './adf-card-view-content-proxy.directive'; +import { CardViewDateItemComponent } from './adf-card-view-dateitem.component'; +import { CardViewItemDispatcherComponent } from './adf-card-view-item-dispatcher.component'; +import { CardViewTextItemComponent } from './adf-card-view-textitem.component'; import { CardViewComponent } from './adf-card-view.component'; describe('AdfCardView', () => { @@ -27,12 +36,32 @@ describe('AdfCardView', () => { beforeEach(async(() => { TestBed.configureTestingModule({ + imports: [ + MdDatepickerModule, + MdIconModule, + MdInputModule, + MdNativeDateModule, + FormsModule + ], declarations: [ - CardViewComponent + CardViewComponent, + CardViewItemDispatcherComponent, + AdfCardViewContentProxyDirective, + CardViewTextItemComponent, + CardViewDateItemComponent ], providers: [ + CardViewUpdateService ] - }).compileComponents(); + }); + + // entryComponents are not supported yet on TestBed, that is why this ugly workaround: + // https://github.com/angular/angular/issues/10760 + TestBed.overrideModule(BrowserDynamicTestingModule, { + set: { entryComponents: [ CardViewTextItemComponent, CardViewDateItemComponent ] } + }); + + TestBed.compileComponents(); })); beforeEach(() => { @@ -41,59 +70,73 @@ describe('AdfCardView', () => { }); it('should render the label and value', async(() => { - component.properties = [new CardViewModel({label: 'My label', value: 'My value'})]; + component.properties = [new CardViewTextItemModel({label: 'My label', value: 'My value', key: 'some key'})]; fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); - let labelValue = fixture.debugElement.query(By.css('.adf-header__label')); + let labelValue = fixture.debugElement.query(By.css('.adf-property-label')); expect(labelValue).not.toBeNull(); expect(labelValue.nativeElement.innerText).toBe('My label'); - let value = fixture.debugElement.query(By.css('.adf-header__value')); + let value = fixture.debugElement.query(By.css('.adf-property-value')); expect(value).not.toBeNull(); expect(value.nativeElement.innerText).toBe('My value'); }); - })); + it('should pass through editable property to the items', () => { + component.editable = true; + component.properties = [new CardViewDateItemModel({ + label: 'My date label', + value: '2017-06-14', + key: 'some-key', + editable: true + })]; + + fixture.detectChanges(); + + let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-some-key"]`)); + expect(datePicker).not.toBeNull('Datepicker should be in DOM'); + }); + it('should render the date in the correct format', async(() => { - component.properties = [new CardViewModel({ - label: 'My date label', value: '2017-06-14', + component.properties = [new CardViewDateItemModel({ + label: 'My date label', value: '2017-06-14', key: 'some key', format: 'MMM DD YYYY' })]; fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); - let labelValue = fixture.debugElement.query(By.css('.adf-header__label')); + let labelValue = fixture.debugElement.query(By.css('.adf-property-label')); expect(labelValue).not.toBeNull(); expect(labelValue.nativeElement.innerText).toBe('My date label'); - let value = fixture.debugElement.query(By.css('.adf-header__value')); + let value = fixture.debugElement.query(By.css('.adf-property-value')); expect(value).not.toBeNull(); expect(value.nativeElement.innerText).toBe('Jun 14 2017'); }); - })); it('should render the default value if the value is empty', async(() => { - component.properties = [new CardViewModel({ + component.properties = [new CardViewTextItemModel({ label: 'My default label', - default: 'default value' + value: null, + default: 'default value', + key: 'some key' })]; fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); - let labelValue = fixture.debugElement.query(By.css('.adf-header__label')); + let labelValue = fixture.debugElement.query(By.css('.adf-property-label')); expect(labelValue).not.toBeNull(); expect(labelValue.nativeElement.innerText).toBe('My default label'); - let value = fixture.debugElement.query(By.css('.adf-header__value')); + let value = fixture.debugElement.query(By.css('.adf-property-value')); expect(value).not.toBeNull(); expect(value.nativeElement.innerText).toBe('default value'); }); - })); }); diff --git a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.ts b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.ts index da0c931bff..0aca314346 100644 --- a/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.ts +++ b/ng2-components/ng2-alfresco-core/src/components/view/adf-card-view.component.ts @@ -16,26 +16,17 @@ */ import { Component, Input } from '@angular/core'; -import * as moment from 'moment'; -import { CardViewModel } from '../../models/card-view.model'; +import { CardViewItem } from '../../interface/card-view-item.interface'; @Component({ selector: 'adf-card-view', templateUrl: './adf-card-view.component.html', - styleUrls: ['./adf-card-view.component.css'] + styleUrls: ['./adf-card-view.component.scss'] }) export class CardViewComponent { + @Input() + properties: CardViewItem []; @Input() - properties: CardViewModel []; - - getPropertyValue(property: CardViewModel): string { - if (!property.value) { - return property.default; - } else if (property.format) { - return moment(property.value).format(property.format); - } - return property.value; - } - + editable: boolean; } diff --git a/ng2-components/ng2-alfresco-core/src/components/view/card-view.module.ts b/ng2-components/ng2-alfresco-core/src/components/view/card-view.module.ts index 3a970e98e8..10ac39bdc3 100644 --- a/ng2-components/ng2-alfresco-core/src/components/view/card-view.module.ts +++ b/ng2-components/ng2-alfresco-core/src/components/view/card-view.module.ts @@ -17,14 +17,34 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { MdButtonModule, MdDatepickerModule, MdIconModule, MdInputModule, MdNativeDateModule } from '@angular/material'; +import { AdfCardViewContentProxyDirective } from './adf-card-view-content-proxy.directive'; +import { CardViewDateItemComponent } from './adf-card-view-dateitem.component'; +import { CardViewItemDispatcherComponent } from './adf-card-view-item-dispatcher.component'; +import { CardViewTextItemComponent } from './adf-card-view-textitem.component'; import { CardViewComponent } from './adf-card-view.component'; @NgModule({ imports: [ - CommonModule + CommonModule, + MdDatepickerModule, + MdNativeDateModule, + MdInputModule, + MdIconModule, + MdButtonModule, + FormsModule ], declarations: [ - CardViewComponent + CardViewComponent, + CardViewItemDispatcherComponent, + AdfCardViewContentProxyDirective, + CardViewTextItemComponent, + CardViewDateItemComponent + ], + entryComponents: [ + CardViewTextItemComponent, + CardViewDateItemComponent ], exports: [ CardViewComponent diff --git a/ng2-components/ng2-alfresco-core/src/interface/card-view-item.interface.ts b/ng2-components/ng2-alfresco-core/src/interface/card-view-item.interface.ts new file mode 100644 index 0000000000..b3496f234e --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/interface/card-view-item.interface.ts @@ -0,0 +1,26 @@ +/*! + * @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. + */ + +export interface CardViewItem { + label: string; + value: any; + key: string; + default?: any; + type: string; + displayValue: string; + editable?: boolean; +} diff --git a/ng2-components/ng2-alfresco-core/src/models/card-view.model.ts b/ng2-components/ng2-alfresco-core/src/models/card-view-baseitem.model.ts similarity index 72% rename from ng2-components/ng2-alfresco-core/src/models/card-view.model.ts rename to ng2-components/ng2-alfresco-core/src/models/card-view-baseitem.model.ts index 9c804d1413..4da54a4adc 100644 --- a/ng2-components/ng2-alfresco-core/src/models/card-view.model.ts +++ b/ng2-components/ng2-alfresco-core/src/models/card-view-baseitem.model.ts @@ -20,21 +20,29 @@ * This object represent the basic structure of a card view. * * - * @returns {CardViewModel} . + * @returns {CardViewBaseItemModel} . */ -export class CardViewModel { +export interface CardViewItemProperties { label: string; value: any; key: any; - format: string; - default: string; + default?: string; + editable?: boolean; +} - constructor(obj?: any) { +export abstract class CardViewBaseItemModel { + label: string; + value: any; + key: any; + default: string; + editable: boolean; + + constructor(obj: CardViewItemProperties) { this.label = obj.label || ''; this.value = obj.value; this.key = obj.key; - this.format = obj.format; this.default = obj.default; + this.editable = obj.editable || false; } } diff --git a/ng2-components/ng2-alfresco-core/src/models/card-view-dateitem.model.ts b/ng2-components/ng2-alfresco-core/src/models/card-view-dateitem.model.ts new file mode 100644 index 0000000000..4ff4f6ef28 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/models/card-view-dateitem.model.ts @@ -0,0 +1,50 @@ +/*! + * @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. + */ + +/** + * + * This object represent the basic structure of a card view. + * + * + * @returns {CardViewDateItemModel} . + */ + +import * as moment from 'moment'; +import { CardViewItem } from '../interface/card-view-item.interface'; +import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model'; + +export interface CardViewDateItemProperties extends CardViewItemProperties { + format?: string; +} + +export class CardViewDateItemModel extends CardViewBaseItemModel implements CardViewItem { + type: string = 'date'; + format: string; + + constructor(obj: CardViewDateItemProperties) { + super(obj); + this.format = obj.format || 'MMM DD YYYY'; + } + + get displayValue() { + if (!this.value) { + return this.default; + } else { + return moment(this.value).format(this.format); + } + } +} diff --git a/ng2-components/ng2-alfresco-core/src/models/card-view-textitem.model.ts b/ng2-components/ng2-alfresco-core/src/models/card-view-textitem.model.ts new file mode 100644 index 0000000000..fccfddad5a --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/models/card-view-textitem.model.ts @@ -0,0 +1,44 @@ +/*! + * @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. + */ + +/** + * + * This object represent the basic structure of a card view. + * + * + * @returns {CardViewTextItemModel} . + */ + +import { CardViewItem } from '../interface/card-view-item.interface'; +import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model'; + +export interface CardViewTextItemProperties extends CardViewItemProperties { + multiline?: boolean; +} +export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem { + type: string = 'text'; + multiline: boolean; + + constructor(obj: CardViewTextItemProperties) { + super(obj); + this.multiline = obj.multiline || false; + } + + get displayValue() { + return this.value || this.default; + } +} diff --git a/ng2-components/ng2-alfresco-core/src/models/index.ts b/ng2-components/ng2-alfresco-core/src/models/index.ts index fff2631f30..956380ce41 100644 --- a/ng2-components/ng2-alfresco-core/src/models/index.ts +++ b/ng2-components/ng2-alfresco-core/src/models/index.ts @@ -15,5 +15,6 @@ * limitations under the License. */ -export * from './card-view.model'; +export * from './card-view-textitem.model'; +export * from './card-view-dateitem.model'; export * from './file.model'; diff --git a/ng2-components/ng2-alfresco-core/src/services/adf-card-view-update.service.ts b/ng2-components/ng2-alfresco-core/src/services/adf-card-view-update.service.ts new file mode 100644 index 0000000000..3821af74ab --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/adf-card-view-update.service.ts @@ -0,0 +1,42 @@ +/*! + * @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 { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; +import { CardViewBaseItemModel } from '../models/card-view-baseitem.model'; + +export interface UpdateNotification { + target: any; + changed: any; +} + +@Injectable() +export class CardViewUpdateService { + + // Observable sources + private itemUpdatedSource = new Subject(); + + // Observable streams + public itemUpdated$ = this.itemUpdatedSource.asObservable(); + + update(property: CardViewBaseItemModel, changed: any) { + this.itemUpdatedSource.next({ + target: property, + changed + }); + } +} diff --git a/ng2-components/ng2-alfresco-core/src/services/index.ts b/ng2-components/ng2-alfresco-core/src/services/index.ts index 366db8fbb2..eb4bbb3393 100644 --- a/ng2-components/ng2-alfresco-core/src/services/index.ts +++ b/ng2-components/ng2-alfresco-core/src/services/index.ts @@ -33,3 +33,4 @@ export * from './alfresco-translate-loader.service'; export * from './app-config.service'; export * from './thumbnail.service'; export * from './upload.service'; +export * from './adf-card-view-update.service'; diff --git a/ng2-components/ng2-alfresco-login/README.md b/ng2-components/ng2-alfresco-login/README.md index 023f0ef82f..e4ca4d87ba 100644 --- a/ng2-components/ng2-alfresco-login/README.md +++ b/ng2-components/ng2-alfresco-login/README.md @@ -77,6 +77,7 @@ export class AppComponent { | needHelpLink | string | | It will change the url of the NEED HELP link in the footer | | registerLink | string | | It will change the url of the REGISTER link in the footer | | logoImageUrl | string | Alfresco logo image | To change the logo image with a customised image | +| copyrightText | string | © 2016 Alfresco Software, Inc. All Rights Reserved. | The copyright text below the login box | | backgroundImageUrl | string | Alfresco background image | To change the background image with a customised image | | fieldsValidation | { [key: string]: any; }, extra?: { [key: string]: any; } | | Use it to customise the validation rules of the login form | | showRememberMe | boolean | false | Toggle `Remember me` checkbox visibility | diff --git a/ng2-components/ng2-alfresco-login/config/webpack.common.js b/ng2-components/ng2-alfresco-login/config/webpack.common.js index f90fe35645..53caec66fd 100644 --- a/ng2-components/ng2-alfresco-login/config/webpack.common.js +++ b/ng2-components/ng2-alfresco-login/config/webpack.common.js @@ -63,8 +63,17 @@ module.exports = { exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { - test: /\.component.scss$/, - use: ['to-string-loader', 'raw-loader', 'sass-loader'], + test: /\.scss$/, + use: [{ + loader: "to-string-loader" + }, { + loader: "raw-loader" + }, { + loader: "sass-loader", + options: { + includePaths: [ path.resolve(__dirname, '../../ng2-alfresco-core/styles')] + } + }], exclude: [/node_modules/, /bundles/, /dist/, /demo/] }, { diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html index 09851f9928..e862f8875e 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.html @@ -107,7 +107,7 @@
    - diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts index df24628fcb..18e2256122 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.spec.ts @@ -157,6 +157,22 @@ describe('AlfrescoLogin', () => { expect(element.querySelector('#login-action-register').innerText).toEqual('LOGIN.ACTION.REGISTER'); }); + describe('Copyright text', () => { + + it('should render the default copyright text', () => { + expect(element.querySelector('[data-automation-id="login-copyright"]')).toBeDefined(); + expect(element.querySelector('[data-automation-id="login-copyright"]').innerText).toEqual('© 2016 Alfresco Software, Inc. All Rights Reserved.'); + }); + + it('should render the customised copyright text', () => { + component.copyrightText = 'customised'; + fixture.detectChanges(); + + expect(element.querySelector('[data-automation-id="login-copyright"]')).toBeDefined(); + expect(element.querySelector('[data-automation-id="login-copyright"]').innerText).toEqual('customised'); + }); + }); + it('should render user and password input fields with default values', () => { expect(element.querySelector('form')).toBeDefined(); expect(element.querySelector('input[type="password"]')).toBeDefined(); diff --git a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts index f430705f8f..cd11040e1a 100644 --- a/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts +++ b/ng2-components/ng2-alfresco-login/src/components/alfresco-login.component.ts @@ -63,6 +63,9 @@ export class AlfrescoLoginComponent implements OnInit { @Input() backgroundImageUrl: string = require('../assets/images/background.svg'); + @Input() + copyrightText: string = '© 2016 Alfresco Software, Inc. All Rights Reserved.'; + @Input() providers: string;