diff --git a/demo-shell-ng2/app.config-dev.json b/demo-shell-ng2/app.config-dev.json index fa12f1e59d..460679a49c 100644 --- a/demo-shell-ng2/app.config-dev.json +++ b/demo-shell-ng2/app.config-dev.json @@ -4,6 +4,9 @@ "application": { "name": "Alfresco" }, + "pagination": { + "size": 25 + }, "activiti": { "rest": { "fields": [ diff --git a/demo-shell-ng2/app.config-prod.json b/demo-shell-ng2/app.config-prod.json index aad45771c8..ea4bda0fed 100644 --- a/demo-shell-ng2/app.config-prod.json +++ b/demo-shell-ng2/app.config-prod.json @@ -3,5 +3,24 @@ "bpmHost": "http://{hostname}", "application": { "name": "Alfresco" + }, + "pagination": { + "size": 25 + }, + "activiti": { + "rest": { + "fields": [ + { + "processId": "0", + "taskId": "7501", + "fieldId": "label10", + "values": [ + { "id": "f1", "name": "Field 1" }, + { "id": "f2", "name": "Field 2" }, + { "id": "f3", "name": "Field 3" } + ] + } + ] + } } } diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts index 3ecfe238c2..c92f64dace 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-list.component.spec.ts @@ -18,7 +18,7 @@ import { DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { Observable } from 'rxjs/Rx'; -import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core'; +import { CoreModule, AlfrescoTranslationService, AppConfigModule } from 'ng2-alfresco-core'; import { AnalyticsReportListComponent } from '../components/analytics-report-list.component'; import { AnalyticsService } from '../services/analytics.service'; import { ReportParametersModel } from '../models/report.model'; @@ -45,7 +45,10 @@ describe('AnalyticsReportListComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + bpmHost: 'http://localhost:9876/bpm' + }) ], declarations: [ AnalyticsReportListComponent diff --git a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts index ac081ba219..d1e5dfbdcd 100644 --- a/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts +++ b/ng2-components/ng2-activiti-analytics/src/components/analytics-report-parameters.component.spec.ts @@ -20,7 +20,7 @@ import { DebugElement, SimpleChange } from '@angular/core'; import { MdTooltipModule, MdButtonModule, OVERLAY_PROVIDERS } from '@angular/material'; import { Observable } from 'rxjs/Rx'; import * as moment from 'moment'; -import { CoreModule, AlfrescoTranslationService } from 'ng2-alfresco-core'; +import { CoreModule, AlfrescoTranslationService, AppConfigModule } from 'ng2-alfresco-core'; import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component'; import { WIDGET_DIRECTIVES } from '../components/widgets/index'; @@ -44,6 +44,9 @@ describe('AnalyticsReportParametersComponent', () => { TestBed.configureTestingModule({ imports: [ CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + bpmHost: 'http://localhost:9876/bpm' + }), MdTooltipModule, MdButtonModule ], diff --git a/ng2-components/ng2-alfresco-core/README.md b/ng2-components/ng2-alfresco-core/README.md index a3b6a7d561..aec4a248b9 100644 --- a/ng2-components/ng2-alfresco-core/README.md +++ b/ng2-components/ng2-alfresco-core/README.md @@ -375,6 +375,80 @@ The supported variables are: | hostname | `location.hostname` | | port | `location.port` | +### Unit testing + +You can also provide custom values for the entire service. +This might become handy when creating unit tests. + +```ts +describe('MyTest', () => { + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) + ] + }); + }); + +}); +``` + +In the example above custom values are applied on the top of all the values the `AppConfigService` has previously loaded. +If there is an 'app.config.json' file loaded at unit test run time then your custom values will overwrite exiting values with the same keys if present. + +## User Preferences Service + +The `UserPreferencesService` allows you to store preferences for the components. +The preferences are bound to a particular `prefix` so the application can switch between different profiles on demand. + +For example upon login you can set the `prefix` as current username: + +```ts +import { UserPreferencesService, AlfrescoAuthenticationService } from 'ng2-alfresco-core'; + +@Component({...}) +class AppComponent { + constructor(private userPreferences: UserPreferencesService, + private authService: AlfrescoAuthenticationService) { + } + + onLoggedIn() { + this.userPreferences.setStoragePrefix( + this.authService.getEcmUsername() + ); + } +} +``` + +As soon as you assign the storage prefix all settings that you get or set via the `UserPreferencesService` will be saved to dedicated profile. + +You can import the service in your controller an use its APIs like below: + +```ts +@Component({...}) +class AppComponent { + constructor(userPreferences: UserPreferencesService) { + + userPreferences.set('myProperty1', 'value1'); + userPreferences.set('myProperty2', 'value2'); + + console.log( + userPreferences.get('myProperty1') + ); + } +} +``` + +The service also provides quick access to a set of the "known" properties used across ADF components. + +Known properties: + +- paginationSize (number) - gets or sets the preferred pagination size + ## Notification Service The Notification Service is implemented on top of the Angular 2 Material Design snackbar. diff --git a/ng2-components/ng2-alfresco-core/index.ts b/ng2-components/ng2-alfresco-core/index.ts index 660c9f1dd5..c0156e408c 100644 --- a/ng2-components/ng2-alfresco-core/index.ts +++ b/ng2-components/ng2-alfresco-core/index.ts @@ -28,6 +28,7 @@ import { CardViewModule } from './src/components/view/card-view.module'; import { CollapsableModule } from './src/components/collapsable/collapsable.module'; import { AdfToolbarComponent } from './src/components/toolbar/toolbar.component'; import { AppConfigModule } from './src/services/app-config.service'; +import { UserPreferencesService } from './src/services/user-preferences.service'; import { AlfrescoAuthenticationService, @@ -72,6 +73,7 @@ export * from './src/events/base.event'; export * from './src/events/base-ui.event'; export * from './src/events/folder-created.event'; export * from './src/models/index'; +export { UserPreferencesService } from './src/services/user-preferences.service'; export * from './src/models/index'; diff --git a/ng2-components/ng2-alfresco-core/src/services/app-config.service.ts b/ng2-components/ng2-alfresco-core/src/services/app-config.service.ts index 9f524c6781..895c373219 100644 --- a/ng2-components/ng2-alfresco-core/src/services/app-config.service.ts +++ b/ng2-components/ng2-alfresco-core/src/services/app-config.service.ts @@ -24,17 +24,14 @@ export class AppConfigService { private config: any = { 'ecmHost': 'http://{hostname}:{port}/ecm', - 'bpmHost': 'http://{hostname}:{port}/bpm', - 'application': { - 'name': 'Alfresco' - } + 'bpmHost': 'http://{hostname}:{port}/bpm' }; configFile: string = null; constructor(private http: Http) {} - get(key: string): T { + get(key: string, defaultValue?: T): T { let result: any = ObjectUtils.getValue(this.config, key); if (typeof result === 'string') { const map = new Map(); @@ -42,18 +39,22 @@ export class AppConfigService { map.set('port', location.port); result = this.formatString(result, map); } + if (result === undefined) { + return defaultValue; + } return result; } - load(resource: string = 'app.config.json'): Promise { + load(resource: string = 'app.config.json', values?: {}): Promise { this.configFile = resource; - return new Promise((resolve, reject) => { + return new Promise(resolve => { + this.config = Object.assign({}, values || {}); this.http.get(resource).subscribe( data => { this.config = Object.assign({}, this.config, data.json() || {}); resolve(this.config); }, - (err) => { + () => { const errorMessage = `Error loading ${resource}`; console.log(errorMessage); resolve(this.config); @@ -74,11 +75,11 @@ export class AppConfigService { } } -export function InitAppConfigServiceProvider(resource: string): any { +export function InitAppConfigServiceProvider(resource: string, values?: {}): any { return { provide: APP_INITIALIZER, useFactory: (configService: AppConfigService) => { - return () => configService.load(resource); + return () => configService.load(resource, values); }, deps: [ AppConfigService @@ -96,12 +97,12 @@ export function InitAppConfigServiceProvider(resource: string): any { ] }) export class AppConfigModule { - static forRoot(resource: string): ModuleWithProviders { + static forRoot(resource: string, values?: {}): ModuleWithProviders { return { ngModule: AppConfigModule, providers: [ AppConfigService, - InitAppConfigServiceProvider(resource) + InitAppConfigServiceProvider(resource, values) ] }; } diff --git a/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.spec.ts b/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.spec.ts new file mode 100644 index 0000000000..e7b7b462f6 --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.spec.ts @@ -0,0 +1,95 @@ +/*! + * @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, async } from '@angular/core/testing'; +import { AppConfigModule } from './app-config.service'; +import { StorageService } from './storage.service'; +import { UserPreferencesService } from './user-preferences.service'; + +describe('UserPreferencesService', () => { + + const defaultPaginationSize: number = 10; + let preferences: UserPreferencesService; + let storage: StorageService; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + AppConfigModule.forRoot('app.config.json', { + 'pagination': { + 'size': defaultPaginationSize + } + }) + ], + providers: [ + StorageService, + UserPreferencesService + ] + }).compileComponents(); + })); + + beforeEach(() => { + preferences = TestBed.get(UserPreferencesService); + storage = TestBed.get(StorageService); + }); + + it('should get default pagination from app config', () => { + expect(preferences.paginationSize).toBe(defaultPaginationSize); + }); + + it('should use [GUEST] as default storage prefix', () => { + expect(preferences.getStoragePrefix()).toBe('GUEST'); + }); + + it('should change storage prefix', () => { + preferences.setStoragePrefix('USER_A'); + expect(preferences.getStoragePrefix()).toBe('USER_A'); + }); + + it('should format property key for default prefix', () => { + expect(preferences.getPropertyKey('propertyA')).toBe('GUEST__propertyA'); + }); + + it('should format property key for custom prefix', () => { + preferences.setStoragePrefix('USER_A'); + expect(preferences.getPropertyKey('propertyA')).toBe('USER_A__propertyA'); + }); + + it('should save value with default prefix', () => { + preferences.set('propertyA', 'valueA'); + const propertyKey = preferences.getPropertyKey('propertyA'); + expect(storage.getItem(propertyKey)).toBe('valueA'); + }); + + it('should save value with custom prefix', () => { + preferences.setStoragePrefix('USER_A'); + preferences.set('propertyA', 'valueA'); + const propertyKey = preferences.getPropertyKey('propertyA'); + expect(storage.getItem(propertyKey)).toBe('valueA'); + }); + + it('should store custom pagination settings for default prefix', () => { + preferences.paginationSize = 5; + expect(preferences.paginationSize).toBe(5); + }); + + it('should return default paginationSize value', () => { + preferences.set('PAGINATION_SIZE', 0); + expect(preferences.paginationSize).toBe(defaultPaginationSize); + }); + +}); diff --git a/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.ts b/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.ts new file mode 100644 index 0000000000..3719eb86eb --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/services/user-preferences.service.ts @@ -0,0 +1,71 @@ +/*! + * @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 { AppConfigService } from './app-config.service'; +import { StorageService } from './storage.service'; + +@Injectable() +export class UserPreferencesService { + + private defaults = { + paginationSize: 25 + }; + + private _storagePrefix: string = 'GUEST'; + + getStoragePrefix(): string { + return this._storagePrefix; + } + + setStoragePrefix(value: string) { + this._storagePrefix = value || 'GUEST'; + } + + constructor( + appConfig: AppConfigService, + private storage: StorageService) { + this.defaults.paginationSize = appConfig.get('pagination.size', 25); + } + + getPropertyKey(property: string): string { + return `${this.getStoragePrefix()}__${property}`; + } + + set(property: string, value: any) { + if (!property) { return; } + + this.storage.setItem( + this.getPropertyKey(property), + value + ); + } + + get(property: string): string { + const key = this.getPropertyKey(property); + return this.storage.getItem(key); + } + + set paginationSize(value: number) { + this.set('PAGINATION_SIZE', value); + } + + get paginationSize(): number { + return Number(this.get('PAGINATION_SIZE')) || this.defaults.paginationSize; + } + +} diff --git a/ng2-components/ng2-alfresco-core/tsconfig.json b/ng2-components/ng2-alfresco-core/tsconfig.json index b5b9140c06..94e7ec120a 100644 --- a/ng2-components/ng2-alfresco-core/tsconfig.json +++ b/ng2-components/ng2-alfresco-core/tsconfig.json @@ -43,7 +43,9 @@ "es2015", "dom" ], - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "noUnusedParameters": true }, "exclude": [ "demo", diff --git a/ng2-components/ng2-alfresco-tag/src/components/tag-actions.component.spec.ts b/ng2-components/ng2-alfresco-tag/src/components/tag-actions.component.spec.ts index 7b5901b19e..58a2791be3 100644 --- a/ng2-components/ng2-alfresco-tag/src/components/tag-actions.component.spec.ts +++ b/ng2-components/ng2-alfresco-tag/src/components/tag-actions.component.spec.ts @@ -18,13 +18,13 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { TagActionsComponent } from '../components/tag-actions.component'; import { DebugElement } from '@angular/core'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { TagService } from '../services/tag.service'; import { MdInputModule } from '@angular/material'; declare let jasmine: any; -describe('Test ng2-alfresco-tag Tag actions list', () => { +describe('TagActionsComponent', () => { let component: any; let fixture: ComponentFixture; @@ -35,7 +35,10 @@ describe('Test ng2-alfresco-tag Tag actions list', () => { TestBed.configureTestingModule({ imports: [ MdInputModule, - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) ], declarations: [ TagActionsComponent diff --git a/ng2-components/ng2-alfresco-tag/src/components/tag-list.component.spec.ts b/ng2-components/ng2-alfresco-tag/src/components/tag-list.component.spec.ts index 9637c091d4..2d4c9efa1b 100644 --- a/ng2-components/ng2-alfresco-tag/src/components/tag-list.component.spec.ts +++ b/ng2-components/ng2-alfresco-tag/src/components/tag-list.component.spec.ts @@ -17,14 +17,14 @@ import { DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { TagList } from './../components/tag-list.component'; import { TagService } from '../services/tag.service'; import { MdInputModule } from '@angular/material'; declare let jasmine: any; -describe('Test ng2-alfresco-tag Tag list All ECM', () => { +describe('TagList', () => { let dataTag = { 'list': { @@ -51,7 +51,10 @@ describe('Test ng2-alfresco-tag Tag list All ECM', () => { TestBed.configureTestingModule({ imports: [ MdInputModule, - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) ], declarations: [ TagList diff --git a/ng2-components/ng2-alfresco-tag/src/components/tag-node-list.component.spec.ts b/ng2-components/ng2-alfresco-tag/src/components/tag-node-list.component.spec.ts index 2c50892ea8..8fc896a0c3 100644 --- a/ng2-components/ng2-alfresco-tag/src/components/tag-node-list.component.spec.ts +++ b/ng2-components/ng2-alfresco-tag/src/components/tag-node-list.component.spec.ts @@ -18,13 +18,13 @@ import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { TagNodeList } from '../components/tag-node-list.component'; import { DebugElement } from '@angular/core'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { TagService } from '../services/tag.service'; import { MdInputModule } from '@angular/material'; declare let jasmine: any; -describe('Test ng2-alfresco-tag Tag relative node list', () => { +describe('TagNodeList', () => { let dataTag = { 'list': { @@ -51,7 +51,10 @@ describe('Test ng2-alfresco-tag Tag relative node list', () => { TestBed.configureTestingModule({ imports: [ MdInputModule, - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) ], declarations: [ TagNodeList diff --git a/ng2-components/ng2-alfresco-tag/src/services/tag.service.spec.ts b/ng2-components/ng2-alfresco-tag/src/services/tag.service.spec.ts index 820fbaa0b1..ff264eafbe 100644 --- a/ng2-components/ng2-alfresco-tag/src/services/tag.service.spec.ts +++ b/ng2-components/ng2-alfresco-tag/src/services/tag.service.spec.ts @@ -16,19 +16,22 @@ */ import { TestBed, async } from '@angular/core/testing'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { TagService } from '../services/tag.service'; declare let jasmine: any; -describe('Tag service', () => { +describe('TagService', () => { let service: TagService; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) ], providers: [ TagService diff --git a/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts b/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts index 722395ca4e..12b9b8129d 100644 --- a/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts +++ b/ng2-components/ng2-alfresco-upload/src/services/upload.service.spec.ts @@ -17,7 +17,7 @@ import { EventEmitter } from '@angular/core'; import { TestBed } from '@angular/core/testing'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { UploadService } from './upload.service'; import { FileModel, FileUploadOptions } from '../models/file.model'; @@ -29,7 +29,10 @@ describe('UploadService', () => { beforeEach(() => { TestBed.configureTestingModule({ imports: [ - CoreModule.forRoot() + CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }) ], providers: [ UploadService diff --git a/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts index 835b24aeec..d08ecdaf5f 100644 --- a/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts +++ b/ng2-components/ng2-alfresco-webscript/src/webscript.component.spec.ts @@ -17,13 +17,13 @@ import { DebugElement } from '@angular/core'; import { ComponentFixture, TestBed, async } from '@angular/core/testing'; -import { CoreModule } from 'ng2-alfresco-core'; +import { CoreModule, AppConfigModule } from 'ng2-alfresco-core'; import { DataTableModule } from 'ng2-alfresco-datatable'; import { WebscriptComponent } from '../src/webscript.component'; declare let jasmine: any; -describe('Test ng2-alfresco-webscript', () => { +describe('WebscriptComponent', () => { let component: WebscriptComponent; let fixture: ComponentFixture; @@ -34,6 +34,9 @@ describe('Test ng2-alfresco-webscript', () => { TestBed.configureTestingModule({ imports: [ CoreModule.forRoot(), + AppConfigModule.forRoot('app.config.json', { + ecmHost: 'http://localhost:9876/ecm' + }), DataTableModule ], declarations: [