diff --git a/demo-shell/resources/i18n/en.json b/demo-shell/resources/i18n/en.json index 7e38849ed2..69fcd147fb 100644 --- a/demo-shell/resources/i18n/en.json +++ b/demo-shell/resources/i18n/en.json @@ -6,6 +6,16 @@ "PROPERTIES": "Properties", "VERSIONS": "Versions" }, + "HOME": { + "TITLE": "Angular components for Alfresco", + "DOCUMENTATION": "Documentation" + }, + "LOGOUT": { + "TITLE": "Logout Page", + "SUB_TITLE": "You are now logged out", + "LOGIN": "Login", + "HOME": "Home" + }, "ADF_VERSION_MANAGER": { "ALLOW_DELETE": "Allow delete", "SHOW_COMMENTS" : "Show comments on versions", diff --git a/demo-shell/src/app.config.json b/demo-shell/src/app.config.json index c97e4774df..176fe88296 100644 --- a/demo-shell/src/app.config.json +++ b/demo-shell/src/app.config.json @@ -2,7 +2,18 @@ "$schema": "../../lib/core/app-config/schema.json", "ecmHost": "http://{hostname}:{port}", "bpmHost": "http://{hostname}:{port}", + "providers": "OAUTH", "contextRootBpm": "activiti-app", + "oauth2": { + "host": "YOUR_AUTH_SERVER", + "clientId": "activiti", + "scope": "openid", + "secret": "", + "implicitFlow": true, + "silentLogin": true, + "redirectUri": "/", + "redirectUriLogout": "/logout" + }, "application": { "name": "Alfresco ADF Application", "copyright": "© 2016 - 2018 Alfresco Software, Inc. All Rights Reserved." diff --git a/demo-shell/src/app/app.component.ts b/demo-shell/src/app/app.component.ts index a99aa77a79..19f2d63c43 100644 --- a/demo-shell/src/app/app.component.ts +++ b/demo-shell/src/app/app.component.ts @@ -16,7 +16,7 @@ */ import { Component, ViewEncapsulation, OnInit } from '@angular/core'; -import { AlfrescoApiService, SettingsService, PageTitleService, StorageService } from '@alfresco/adf-core'; +import { AlfrescoApiService, PageTitleService } from '@alfresco/adf-core'; import { Router } from '@angular/router'; @Component({ @@ -27,15 +27,12 @@ import { Router } from '@angular/router'; }) export class AppComponent implements OnInit { - constructor(private settingsService: SettingsService, - private storage: StorageService, - private pageTitleService: PageTitleService, + constructor(private pageTitleService: PageTitleService, private alfrescoApiService: AlfrescoApiService, private router: Router) { } ngOnInit() { - this.setProvider(); this.pageTitleService.setTitle('title'); @@ -46,10 +43,4 @@ export class AppComponent implements OnInit { } }); } - - private setProvider() { - if (this.storage.hasItem(`providers`)) { - this.settingsService.setProviders(this.storage.getItem(`providers`)); - } - } } diff --git a/demo-shell/src/app/app.module.ts b/demo-shell/src/app/app.module.ts index ee3b482a9c..de5d08986e 100644 --- a/demo-shell/src/app/app.module.ts +++ b/demo-shell/src/app/app.module.ts @@ -11,6 +11,7 @@ import { AppComponent } from './app.component'; import { AdfModule } from './adf.module'; import { MaterialModule } from './material.module'; import { LoginComponent } from './components/login/login.component'; +import { LogoutComponent } from './components/logout/logout.component'; import { SettingsComponent } from './components/settings/settings.component'; import { AppLayoutComponent } from './components/app-layout/app-layout.component'; import { HomeComponent } from './components/home/home.component'; @@ -71,6 +72,7 @@ import { NotificationsComponent } from './components/notifications/notifications declarations: [ AppComponent, LoginComponent, + LogoutComponent, SettingsComponent, AppLayoutComponent, HomeComponent, diff --git a/demo-shell/src/app/app.routes.ts b/demo-shell/src/app/app.routes.ts index 5524701459..7849946b19 100644 --- a/demo-shell/src/app/app.routes.ts +++ b/demo-shell/src/app/app.routes.ts @@ -17,11 +17,12 @@ import { ModuleWithProviders } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { AuthGuard, AuthGuardBpm, AuthGuardEcm, ErrorContentComponent } from '@alfresco/adf-core'; +import { AuthGuard, AuthGuardEcm, ErrorContentComponent, AuthGuardBpm } from '@alfresco/adf-core'; import { AppLayoutComponent } from './components/app-layout/app-layout.component'; import { LoginComponent } from './components/login/login.component'; import { SettingsComponent } from './components/settings/settings.component'; import { HomeComponent } from './components/home/home.component'; +import { LogoutComponent } from './components/logout/logout.component'; import { AboutComponent } from './components/about/about.component'; import { ProcessServiceComponent } from './components/process-service/process-service.component'; import { ShowDiagramComponent } from './components/process-service/show-diagram.component'; @@ -52,8 +53,9 @@ import { NotificationsComponent } from './components/notifications/notifications export const appRoutes: Routes = [ { path: 'login', component: LoginComponent }, + { path: 'logout', component: LogoutComponent }, { path: 'settings', component: SettingsComponent }, - { path: 'files/:nodeId/view', component: FileViewComponent, canActivate: [AuthGuardEcm], outlet: 'overlay' }, + { path: 'files/:nodeId/view', component: FileViewComponent, canActivate: [ AuthGuardEcm ], outlet: 'overlay' }, { path: 'preview/blob', component: BlobPreviewComponent, outlet: 'overlay', pathMatch: 'full' }, { path: 'preview/s/:id', component: SharedLinkViewComponent }, { @@ -226,4 +228,4 @@ export const appRoutes: Routes = [ } ]; -export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes); +export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { initialNavigation: true }); diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.html b/demo-shell/src/app/components/app-layout/app-layout.component.html index 100f20159f..5fba1de75c 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.html +++ b/demo-shell/src/app/components/app-layout/app-layout.component.html @@ -37,7 +37,7 @@ {{link.icon}}
{{link.title | translate }}
- + exit_to_app
Logout
diff --git a/demo-shell/src/app/components/app-layout/app-layout.component.ts b/demo-shell/src/app/components/app-layout/app-layout.component.ts index 3cf40629b4..9cf5138759 100644 --- a/demo-shell/src/app/components/app-layout/app-layout.component.ts +++ b/demo-shell/src/app/components/app-layout/app-layout.component.ts @@ -16,7 +16,7 @@ */ import { Component, ViewEncapsulation, OnInit } from '@angular/core'; -import { UserPreferencesService, AppConfigService } from '@alfresco/adf-core'; +import { UserPreferencesService, AppConfigService, AlfrescoApiService } from '@alfresco/adf-core'; @Component({ templateUrl: 'app-layout.component.html', @@ -54,18 +54,23 @@ export class AppLayoutComponent implements OnInit { expandedSidenav = false; + enabelRedirect = true; ngOnInit() { const expand = this.config.get('sideNav.expandedSidenav'); const preserveState = this.config.get('sideNav.preserveState'); - if (preserveState && expand) { + if (preserveState && expand) { this.expandedSidenav = (this.userpreference.get('expandedSidenav', expand.toString()) === 'true'); } else if (expand) { this.expandedSidenav = expand; } } - constructor( private userpreference: UserPreferencesService, private config: AppConfigService) { + + constructor(private userpreference: UserPreferencesService, private config: AppConfigService, private alfrescoApiService: AlfrescoApiService) { + if (this.alfrescoApiService.getInstance().isOauthConfiguration()) { + this.enabelRedirect = false; + } } setState(state) { diff --git a/demo-shell/src/app/components/files/files.component.ts b/demo-shell/src/app/components/files/files.component.ts index c620697d37..a12cb187be 100644 --- a/demo-shell/src/app/components/files/files.component.ts +++ b/demo-shell/src/app/components/files/files.component.ts @@ -25,7 +25,7 @@ import { MatDialog } from '@angular/material'; import { ActivatedRoute, Params, Router } from '@angular/router'; import { MinimalNodeEntity, NodePaging, Pagination, MinimalNodeEntryEntity, SiteEntry } from 'alfresco-js-api'; import { - AuthenticationService, AppConfigService, ContentService, TranslationService, + AuthenticationService, ContentService, TranslationService, FileUploadEvent, FolderCreatedEvent, LogService, NotificationService, UploadService, DataColumn, DataRow, UserPreferencesService, PaginationComponent, FormValues, DisplayMode, UserPreferenceValues, InfinitePaginationComponent @@ -56,7 +56,7 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy { displayMode = DisplayMode.List; includeFields = ['isFavorite', 'isLocked', 'aspectNames']; - baseShareUrl = this.appConfig.get('ecmHost') + '/preview/s/'; + baseShareUrl = this.preference.ecmHost + '/preview/s/'; toolbarColor = 'default'; @@ -191,7 +191,6 @@ export class FilesComponent implements OnInit, OnChanges, OnDestroy { private router: Router, private logService: LogService, private preference: UserPreferencesService, - private appConfig: AppConfigService, private preview: PreviewService, @Optional() private route: ActivatedRoute, public authenticationService: AuthenticationService) { diff --git a/demo-shell/src/app/components/home/home.component.html b/demo-shell/src/app/components/home/home.component.html index 7d7268f64b..48bc34b877 100644 --- a/demo-shell/src/app/components/home/home.component.html +++ b/demo-shell/src/app/components/home/home.component.html @@ -2,10 +2,10 @@

ADF

-

Angular components for Alfresco

+

{{ 'APP.HOME.TITLE' | translate}}

diff --git a/demo-shell/src/app/components/login/login.component.html b/demo-shell/src/app/components/login/login.component.html index 9a4ccaeb74..9b62c9e918 100644 --- a/demo-shell/src/app/components/login/login.component.html +++ b/demo-shell/src/app/components/login/login.component.html @@ -1,24 +1,6 @@
-

- - {{ 'LOGIN.CONTENT_SERVICES'| translate }} - -

-

- - {{ 'LOGIN.PROCESS_SERVICES'| translate }} - -

-

- - {{ 'LOGIN.CONTENT_SERVICES'| translate }} - -

-

- - {{ 'LOGIN.PROCESS_SERVICES'| translate }} - -

+

+
+

{{ 'APP.LOGOUT.TITLE' | translate}}

+

{{ 'APP.LOGOUT.SUB_TITLE' | translate}}

+
+ + + +
+ diff --git a/demo-shell/src/app/components/logout/logout.component.scss b/demo-shell/src/app/components/logout/logout.component.scss new file mode 100644 index 0000000000..53f059cd80 --- /dev/null +++ b/demo-shell/src/app/components/logout/logout.component.scss @@ -0,0 +1,39 @@ +:host { + display: flex; + justify-content: center; + align-items: center; +} + +.adf-logout-header-background { + overflow: hidden; +} + +.adf-logout-section { + text-align: center; + padding-top: 60px; +} + +.adf-logout-headline { + + h1 { + font-size: 56px; + font-weight: 300; + line-height: 56px; + margin: 15px 5px; + } + + h2 { + font-size: 18px; + font-weight: 300; + line-height: 28px; + margin: 15px 0 25px 0; + } +} + +.adf-logout-docs-button { + margin: 30px; +} + +.adf-logout-login { + float: left; +} diff --git a/demo-shell/src/app/components/logout/logout.component.ts b/demo-shell/src/app/components/logout/logout.component.ts new file mode 100644 index 0000000000..49f0b16ce6 --- /dev/null +++ b/demo-shell/src/app/components/logout/logout.component.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 { Component } from '@angular/core'; + +@Component({ + selector: 'app-logout', + templateUrl: './logout.component.html', + styleUrls: ['./logout.component.scss'] +}) +export class LogoutComponent {} diff --git a/demo-shell/src/app/components/settings/settings.component.html b/demo-shell/src/app/components/settings/settings.component.html index 316962ffd0..444f8236b9 100644 --- a/demo-shell/src/app/components/settings/settings.component.html +++ b/demo-shell/src/app/components/settings/settings.component.html @@ -1 +1 @@ - + diff --git a/demo-shell/src/app/components/settings/settings.component.ts b/demo-shell/src/app/components/settings/settings.component.ts index 8c82578c81..b1e3686548 100644 --- a/demo-shell/src/app/components/settings/settings.component.ts +++ b/demo-shell/src/app/components/settings/settings.component.ts @@ -16,7 +16,8 @@ */ import { Component } from '@angular/core'; -import { LogService } from '@alfresco/adf-core'; +import { LogService, AuthenticationService, AlfrescoApiService } from '@alfresco/adf-core'; +import { Router } from '@angular/router'; @Component({ selector: 'app-settings', @@ -24,10 +25,23 @@ import { LogService } from '@alfresco/adf-core'; }) export class SettingsComponent { - constructor(public logService: LogService) { + constructor(private router: Router, + private authService: AuthenticationService, + private alfrescoApiService: AlfrescoApiService, + public logService: LogService) { } onError(error: string) { this.logService.log(error); } + + onCancel() { + this.router.navigate(['/']); + } + + onSuccess() { + this.authService.removeTicket(); + this.alfrescoApiService.reset(); + this.router.navigate(['/']); + } } diff --git a/docs/core/logout.directive.md b/docs/core/logout.directive.md index 7525c552a4..e0908269e3 100644 --- a/docs/core/logout.directive.md +++ b/docs/core/logout.directive.md @@ -13,6 +13,14 @@ Logs the user out when the decorated element is clicked. ``` +### Properties + +| Name | Type | Default value | Description | +| -- | -- | -- | -- | +| redirectUri | `string` | 'login' | Uri to be redirect after the logout | +| enabelRedirect | `boolean` | 'true' | enable/disable redirect after logout | + + ## See also - [Login component](login.component.md) diff --git a/docs/core/menu-button.model.md b/docs/core/menu-button.model.md index c9bca4fddb..24bb3211a6 100644 --- a/docs/core/menu-button.model.md +++ b/docs/core/menu-button.model.md @@ -19,6 +19,7 @@ let button = new MenuButton({ isVisible: this.isItemValid.bind(this) }); ``` +## Class members ## Properties diff --git a/lib/content-services/dialogs/folder.dialog.ts b/lib/content-services/dialogs/folder.dialog.ts index 3180f19b78..d5406f3649 100644 --- a/lib/content-services/dialogs/folder.dialog.ts +++ b/lib/content-services/dialogs/folder.dialog.ts @@ -42,6 +42,8 @@ export class FolderDialogComponent implements OnInit { @Output() error: EventEmitter = new EventEmitter(); + /** Emitted when the edit/create folder is successfully created/mmodified + */ @Output() success: EventEmitter = new EventEmitter(); diff --git a/lib/content-services/document-list/services/document-actions.service.spec.ts b/lib/content-services/document-list/services/document-actions.service.spec.ts index ca4c85eda7..f928d9e6cf 100644 --- a/lib/content-services/document-list/services/document-actions.service.spec.ts +++ b/lib/content-services/document-list/services/document-actions.service.spec.ts @@ -20,6 +20,9 @@ import { AppConfigService, ContentService, StorageService, + UserPreferencesService, + setupTestBed, + CoreModule, TranslationMock } from '@alfresco/adf-core'; import { FileNode, FolderNode } from '../../mock'; @@ -28,16 +31,25 @@ import { DocumentActionsService } from './document-actions.service'; import { DocumentListService } from './document-list.service'; import { NodeActionsService } from './node-actions.service'; import { Observable } from 'rxjs/Observable'; +import { TestBed } from '@angular/core/testing'; describe('DocumentActionsService', () => { let service: DocumentActionsService; let documentListService: DocumentListService; let nodeActionsService: NodeActionsService; + let userPreferences; + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ] + }); beforeEach(() => { + userPreferences = TestBed.get(UserPreferencesService); let contentService = new ContentService(null, null, null, null); - let alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService()); + let alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService()); documentListService = new DocumentListService(null, contentService, alfrescoApiService, null, null); service = new DocumentActionsService(null, null, new TranslationMock(), documentListService, contentService); diff --git a/lib/content-services/document-list/services/document-list.service.spec.ts b/lib/content-services/document-list/services/document-list.service.spec.ts index 5ff2213eb0..993b41fe0c 100644 --- a/lib/content-services/document-list/services/document-list.service.spec.ts +++ b/lib/content-services/document-list/services/document-list.service.spec.ts @@ -16,8 +16,9 @@ */ import { AlfrescoApiServiceMock, AlfrescoApiService, - AppConfigService, StorageService, ContentService } from '@alfresco/adf-core'; + AppConfigService, StorageService, ContentService, UserPreferencesService, setupTestBed, CoreModule } from '@alfresco/adf-core'; import { DocumentListService } from './document-list.service'; +import { TestBed } from '@angular/core/testing'; declare let jasmine: any; @@ -25,6 +26,7 @@ describe('DocumentListService', () => { let service: DocumentListService; let alfrescoApiService: AlfrescoApiService; + let userPreferences: UserPreferencesService; let fakeEntryNode = { 'entry': { @@ -87,9 +89,17 @@ describe('DocumentListService', () => { } }; + setupTestBed({ + imports: [ + CoreModule.forRoot() + ] + }); + beforeEach(() => { + userPreferences = TestBed.get(UserPreferencesService); + let contentService = new ContentService(null, null, null, null); - alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService()); + alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService()); service = new DocumentListService(null, contentService, alfrescoApiService, null, null); jasmine.Ajax.install(); }); diff --git a/lib/content-services/document-list/services/folder-actions.service.spec.ts b/lib/content-services/document-list/services/folder-actions.service.spec.ts index 2def680c61..bbc7e76814 100644 --- a/lib/content-services/document-list/services/folder-actions.service.spec.ts +++ b/lib/content-services/document-list/services/folder-actions.service.spec.ts @@ -16,7 +16,7 @@ */ import { TestBed } from '@angular/core/testing'; -import { AlfrescoApiServiceMock, AppConfigService, StorageService, ContentService, setupTestBed, CoreModule, TranslationMock } from '@alfresco/adf-core'; +import { AlfrescoApiServiceMock, AppConfigService, StorageService, ContentService, setupTestBed, CoreModule, TranslationMock, UserPreferencesService } from '@alfresco/adf-core'; import { Observable } from 'rxjs/Observable'; import { FileNode, FolderNode } from '../../mock'; import { ContentActionHandler } from '../models/content-action.model'; @@ -27,6 +27,7 @@ describe('FolderActionsService', () => { let service: FolderActionsService; let documentListService: DocumentListService; + let userPreferences: UserPreferencesService; setupTestBed({ imports: [ @@ -38,8 +39,10 @@ describe('FolderActionsService', () => { let appConfig: AppConfigService = TestBed.get(AppConfigService); appConfig.config.ecmHost = 'http://localhost:9876/ecm'; + userPreferences = TestBed.get(UserPreferencesService); + let contentService = new ContentService(null, null, null, null); - let alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService()); + let alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService()); documentListService = new DocumentListService(null, contentService, alfrescoApiService, null, null); service = new FolderActionsService(null, documentListService, contentService, new TranslationMock()); }); diff --git a/lib/content-services/social/services/rating.service.spec.ts b/lib/content-services/social/services/rating.service.spec.ts index 9fb01c1eed..b1575c3191 100644 --- a/lib/content-services/social/services/rating.service.spec.ts +++ b/lib/content-services/social/services/rating.service.spec.ts @@ -15,17 +15,27 @@ * limitations under the License. */ -import { AlfrescoApiServiceMock, AppConfigService, StorageService } from '@alfresco/adf-core'; +import { AlfrescoApiServiceMock, AppConfigService, StorageService, setupTestBed, CoreModule, UserPreferencesService } from '@alfresco/adf-core'; import { RatingService } from './rating.service'; +import { TestBed } from '@angular/core/testing'; declare let jasmine: any; describe('Rating service', () => { let service; + let userPreferences: UserPreferencesService; + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ] + }); beforeEach(() => { - service = new RatingService(new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService())); + userPreferences = TestBed.get(UserPreferencesService); + + service = new RatingService(new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService())); }); beforeEach(() => { diff --git a/lib/content-services/tag/services/tag.service.spec.ts b/lib/content-services/tag/services/tag.service.spec.ts index 0932fdda95..9afb1b57e5 100644 --- a/lib/content-services/tag/services/tag.service.spec.ts +++ b/lib/content-services/tag/services/tag.service.spec.ts @@ -15,17 +15,26 @@ * limitations under the License. */ -import { AlfrescoApiServiceMock, LogService, AppConfigService, StorageService } from '@alfresco/adf-core'; +import { AlfrescoApiServiceMock, LogService, AppConfigService, StorageService, setupTestBed, CoreModule, UserPreferencesService } from '@alfresco/adf-core'; import { TagService } from './tag.service'; +import { TestBed } from '@angular/core/testing'; declare let jasmine: any; describe('TagService', () => { let service: TagService; + let userPreferences: UserPreferencesService; + + setupTestBed({ + imports: [ + CoreModule.forRoot() + ] + }); beforeEach(() => { - service = new TagService(new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService()), new LogService(new AppConfigService(null))); + userPreferences = TestBed.get(UserPreferencesService); + service = new TagService(new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService()), new LogService(new AppConfigService(null))); }); beforeEach(() => { diff --git a/lib/core/about/about.component.ts b/lib/core/about/about.component.ts index b322d8adc4..0c7bf44143 100644 --- a/lib/core/about/about.component.ts +++ b/lib/core/about/about.component.ts @@ -18,10 +18,10 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Http } from '@angular/http'; import { AuthenticationService } from '../services/authentication.service'; -import { AppConfigService } from '../app-config/app-config.service'; import { BpmProductVersionModel, EcmProductVersionModel } from '../models/product-version.model'; import { DiscoveryApiService } from '../services/discovery-api.service'; import { ObjectDataTableAdapter } from '../datatable/data/object-datatable-adapter'; +import { UserPreferencesService } from '../services/user-preferences.service'; @Component({ selector: 'adf-about', @@ -44,7 +44,7 @@ export class AboutComponent implements OnInit { bpmVersion: BpmProductVersionModel = null; constructor(private http: Http, - private appConfig: AppConfigService, + private userPreference: UserPreferencesService, private authService: AuthenticationService, private discovery: DiscoveryApiService) { } @@ -114,8 +114,8 @@ export class AboutComponent implements OnInit { }); - this.ecmHost = this.appConfig.get('ecmHost'); - this.bpmHost = this.appConfig.get('bpmHost'); + this.ecmHost = this.userPreference.ecmHost; + this.bpmHost = this.userPreference.bpmHost; } private gitHubLinkCreation(alfrescoPackagesTableRepresentation): void { diff --git a/lib/core/app-config/schema.json b/lib/core/app-config/schema.json index 1f25414388..473b6e040e 100644 --- a/lib/core/app-config/schema.json +++ b/lib/core/app-config/schema.json @@ -461,12 +461,17 @@ "oauth2": { "description": "AUTH configuration parameters", "type": "object", - "required": [ "host", "clientId", "secret" ], + "required": [ "host", "clientId", "secret", "scope" ], "properties": { "host": { "type": "string" }, + "silentLogin": { "type": "boolean" }, "authPath": { "type": "string" }, "clientId": { "type": "string" }, - "secret": { "type": "string" } + "secret": { "type": "string" }, + "redirectUri": { "type": "string" }, + "redirectUriLogout": { "type": "string" }, + "silentRefreshRedirectUri": { "type": "string" }, + "scope": { "type": "string" } } }, "adf-version-manager": { diff --git a/lib/core/core.module.ts b/lib/core/core.module.ts index 9e0acf10fd..568d50240f 100644 --- a/lib/core/core.module.ts +++ b/lib/core/core.module.ts @@ -17,6 +17,7 @@ import { CommonModule, DatePipe } from '@angular/common'; import { HttpClient, HttpClientModule } from '@angular/common/http'; + import { APP_INITIALIZER, NgModule, ModuleWithProviders } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; diff --git a/lib/core/directives/logout.directive.spec.ts b/lib/core/directives/logout.directive.spec.ts index 8e6b5c8d71..398d772323 100644 --- a/lib/core/directives/logout.directive.spec.ts +++ b/lib/core/directives/logout.directive.spec.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component } from '@angular/core'; +import { Component, ContentChildren } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Router } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; @@ -23,56 +23,152 @@ import { Observable } from 'rxjs/Observable'; import { AuthenticationService } from '../services'; import { setupTestBed } from '../testing/setupTestBed'; import { CoreModule } from '../core.module'; +import { LogoutDirective } from './logout.directive'; describe('LogoutDirective', () => { - @Component({ - selector: 'adf-test-component', - template: '' - }) - class TestComponent {} + describe('No input', () => { - let fixture: ComponentFixture; - let router: Router; - let authService: AuthenticationService; + @Component({ + selector: 'adf-test-component', + template: '' + }) + class TestComponent { + @ContentChildren(LogoutDirective) + logoutDirective: LogoutDirective; + } + + let fixture: ComponentFixture; + let router: Router; + let authService: AuthenticationService; + + setupTestBed({ + imports: [ + CoreModule.forRoot(), + RouterTestingModule + ], + declarations: [ + TestComponent + ] + }); + + beforeEach(() => { + router = TestBed.get(Router); + authService = TestBed.get(AuthenticationService); + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + }); + + it('should redirect to login on click', () => { + spyOn(router, 'navigate').and.callThrough(); + spyOn(authService, 'logout').and.returnValue(Observable.of(true)); + + const button = fixture.nativeElement.querySelector('button'); + button.click(); + + expect(authService.logout).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(['/login']); + }); + + it('should redirect to login even on logout error', () => { + spyOn(router, 'navigate').and.callThrough(); + spyOn(authService, 'logout').and.returnValue(Observable.throw('err')); + + const button = fixture.nativeElement.querySelector('button'); + button.click(); + + expect(authService.logout).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(['/login']); + }); - setupTestBed({ - imports: [ - CoreModule.forRoot(), - RouterTestingModule - ], - declarations: [ - TestComponent - ] }); - beforeEach(() => { - router = TestBed.get(Router); - authService = TestBed.get(AuthenticationService); - fixture = TestBed.createComponent(TestComponent); - fixture.detectChanges(); + describe('redirectUri', () => { + + @Component({ + selector: 'adf-test-component', + template: '' + }) + class TestComponent { + @ContentChildren(LogoutDirective) + logoutDirective: LogoutDirective; + } + + let fixture: ComponentFixture; + let router: Router; + let authService: AuthenticationService; + + setupTestBed({ + imports: [ + CoreModule.forRoot(), + RouterTestingModule + ], + declarations: [ + TestComponent + ] + }); + + beforeEach(() => { + router = TestBed.get(Router); + authService = TestBed.get(AuthenticationService); + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + }); + + it('should redirect to the the input redirectUri on click if present', () => { + spyOn(router, 'navigate').and.callThrough(); + spyOn(authService, 'logout').and.returnValue(Observable.of(true)); + + const button = fixture.nativeElement.querySelector('button'); + button.click(); + + expect(authService.logout).toHaveBeenCalled(); + expect(router.navigate).toHaveBeenCalledWith(['/myCustomUri']); + }); + }); - it('should redirect to login on click', () => { - spyOn(router, 'navigate').and.callThrough(); - spyOn(authService, 'logout').and.returnValue(Observable.of(true)); + describe('redirectUri', () => { - const button = fixture.nativeElement.querySelector('button'); - button.click(); + @Component({ + selector: 'adf-test-component', + template: '' + }) + class TestComponent { + @ContentChildren(LogoutDirective) + logoutDirective: LogoutDirective; + } - expect(authService.logout).toHaveBeenCalled(); - expect(router.navigate).toHaveBeenCalledWith([ '/login' ]); - }); + let fixture: ComponentFixture; + let router: Router; + let authService: AuthenticationService; - it('should redirect to login even on logout error', () => { - spyOn(router, 'navigate').and.callThrough(); - spyOn(authService, 'logout').and.returnValue(Observable.throw('err')); + setupTestBed({ + imports: [ + CoreModule.forRoot(), + RouterTestingModule + ], + declarations: [ + TestComponent + ] + }); - const button = fixture.nativeElement.querySelector('button'); - button.click(); + beforeEach(() => { + router = TestBed.get(Router); + authService = TestBed.get(AuthenticationService); + fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + }); - expect(authService.logout).toHaveBeenCalled(); - expect(router.navigate).toHaveBeenCalledWith([ '/login' ]); + it('should not redirect if enabelRedirect is false', () => { + spyOn(router, 'navigate').and.callThrough(); + spyOn(authService, 'logout').and.returnValue(Observable.of(true)); + const button = fixture.nativeElement.querySelector('button'); + button.click(); + + expect(authService.logout).toHaveBeenCalled(); + expect(router.navigate).not.toHaveBeenCalled(); + }); }); }); diff --git a/lib/core/directives/logout.directive.ts b/lib/core/directives/logout.directive.ts index 30dcb4169b..b85f21bb17 100644 --- a/lib/core/directives/logout.directive.ts +++ b/lib/core/directives/logout.directive.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Directive, ElementRef, OnInit, Renderer2 } from '@angular/core'; +import { Input, Directive, ElementRef, OnInit, Renderer2 } from '@angular/core'; import { Router } from '@angular/router'; import { AuthenticationService } from '../services/authentication.service'; @@ -24,11 +24,18 @@ import { AuthenticationService } from '../services/authentication.service'; }) export class LogoutDirective implements OnInit { - constructor( - private elementRef: ElementRef, - private renderer: Renderer2, - private router: Router, - private auth: AuthenticationService) { + /** Uri to be redirect after the logout default value login */ + @Input() + redirectUri: string = '/login'; + + /** Enable redirect after logout */ + @Input() + enabelRedirect: boolean = true; + + constructor(private elementRef: ElementRef, + private renderer: Renderer2, + private router: Router, + private auth: AuthenticationService) { } ngOnInit() { @@ -42,12 +49,14 @@ export class LogoutDirective implements OnInit { logout() { this.auth.logout().subscribe( - () => this.redirectToLogin(), - () => this.redirectToLogin() + () => this.redirectToUri(), + () => this.redirectToUri() ); } - redirectToLogin() { - this.router.navigate(['/login']); + redirectToUri() { + if (this.enabelRedirect) { + this.router.navigate([this.redirectUri]); + } } } diff --git a/lib/core/directives/node-favorite.directive.spec.ts b/lib/core/directives/node-favorite.directive.spec.ts index 81ea5668ea..56ae3ee58f 100644 --- a/lib/core/directives/node-favorite.directive.spec.ts +++ b/lib/core/directives/node-favorite.directive.spec.ts @@ -16,20 +16,28 @@ */ import { SimpleChange } from '@angular/core'; -import { fakeAsync, tick } from '@angular/core/testing'; +import { fakeAsync, tick, TestBed } from '@angular/core/testing'; import { NodeFavoriteDirective } from './node-favorite.directive'; import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock'; import { AppConfigService } from '../app-config/app-config.service'; import { StorageService } from '../services/storage.service'; -import { AlfrescoApiService } from '../services/alfresco-api.service'; +import { UserPreferencesService } from '../services/user-preferences.service'; +import { setupTestBed } from '../testing/setupTestBed'; +import { CoreTestingModule } from '../testing/core.testing.module'; describe('NodeFavoriteDirective', () => { let directive; - let alfrescoApiService: AlfrescoApiService; + let alfrescoApiService; + let userPreferences; + + setupTestBed({ + imports: [CoreTestingModule] + }); beforeEach(() => { - alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), new StorageService()); + userPreferences = TestBed.get(UserPreferencesService); + alfrescoApiService = new AlfrescoApiServiceMock(new AppConfigService(null), userPreferences, new StorageService()); directive = new NodeFavoriteDirective( alfrescoApiService); }); diff --git a/lib/core/i18n/en.json b/lib/core/i18n/en.json index c0cd55bc64..de7ab5f01e 100644 --- a/lib/core/i18n/en.json +++ b/lib/core/i18n/en.json @@ -118,6 +118,7 @@ "ERROR_PLURAL": "{{ number }} items couldn't be deleted" }, "HOST_SETTINGS": { + "REQUIRED": "The field is required", "CS_URL_ERROR": "Content Services address doesn't match the URL format", "PS_URL_ERROR": "Process Services address doesn't match the URL format", "TITLE": "Settings", @@ -125,7 +126,11 @@ "BP-HOST": "Process Services URL", "BACK": "Back", "APPLY": "APPLY", - "NOT_VALID": "http(s)://host|ip:port(/path) not recognized, try a different URL." + "NOT_VALID": "http(s)://host|ip:port(/path) not recognized, try a different URL.", + "REDIRECT": "Redirect Uri", + "SILENT": "Silent Login", + "SCOPE": "Scope", + "CLIENT": "ClientId" }, "CARDVIEW": { "VALIDATORS": { @@ -193,7 +198,8 @@ "BUTTON": { "LOGIN": "SIGN IN", "CHECKING": "CHECKING", - "WELCOME": "WELCOME" + "WELCOME": "WELCOME", + "SSO": "SIGN IN SSO" }, "ACTION": { "HELP": "NEED HELP?", diff --git a/lib/core/login/components/login.component.html b/lib/core/login/components/login.component.html index 0843da66f6..752d62ca87 100644 --- a/lib/core/login/components/login.component.html +++ b/lib/core/login/components/login.component.html @@ -1,6 +1,6 @@