From 2f4048a859c159b347162dd6ec582a57805b5c44 Mon Sep 17 00:00:00 2001 From: Cilibiu Bogdan Date: Mon, 17 Sep 2018 12:40:31 +0300 Subject: [PATCH] [ACA] Dialogs - close on navigation by default (#634) * close modals on navigation by default * lint * modals effect and action * add to store module * register in module * close modals if auth fails * rename action * change dialog selector --- e2e/pages/page.ts | 176 +++++++++++++----------- src/app/app.component.ts | 11 +- src/app/material.module.ts | 9 +- src/app/store/actions.ts | 1 + src/app/store/actions/modals.actions.ts | 33 +++++ src/app/store/app-store.module.ts | 6 +- src/app/store/effects.ts | 1 + src/app/store/effects/modals.effects.ts | 41 ++++++ 8 files changed, 190 insertions(+), 88 deletions(-) create mode 100644 src/app/store/actions/modals.actions.ts create mode 100644 src/app/store/effects/modals.effects.ts diff --git a/e2e/pages/page.ts b/e2e/pages/page.ts index 324fb8f57..c9e0a27d6 100755 --- a/e2e/pages/page.ts +++ b/e2e/pages/page.ts @@ -23,107 +23,125 @@ * along with Alfresco. If not, see . */ -import { browser, element, by, ElementFinder, promise, ExpectedConditions as EC } from 'protractor'; +import { + browser, + element, + by, + ElementFinder, + promise, + ExpectedConditions as EC +} from 'protractor'; import { BROWSER_WAIT_TIMEOUT } from './../configs'; export abstract class Page { - private static USE_HASH_STRATEGY = true; + private static USE_HASH_STRATEGY = true; - private locators = { - app: by.css('app-root'), - layout: by.css('app-layout'), - overlay: by.css('.cdk-overlay-container'), - dialogContainer: by.css('.mat-dialog-container[role]'), - snackBarContainer: '.cdk-overlay-pane .mat-snack-bar-container', - snackBar: '.mat-simple-snackbar', - snackBarAction: '.mat-simple-snackbar-action button', + private locators = { + app: by.css('app-root'), + layout: by.css('app-layout'), + overlay: by.css('.cdk-overlay-container'), + dialogContainer: by.css('.mat-dialog-container'), + snackBarContainer: '.cdk-overlay-pane .mat-snack-bar-container', + snackBar: '.mat-simple-snackbar', + snackBarAction: '.mat-simple-snackbar-action button', - genericError: 'aca-generic-error', - genericErrorIcon: 'aca-generic-error .mat-icon', - genericErrorTitle: '.generic-error__title' - }; + genericError: 'aca-generic-error', + genericErrorIcon: 'aca-generic-error .mat-icon', + genericErrorTitle: '.generic-error__title' + }; - public app: ElementFinder = element(this.locators.app); - public layout: ElementFinder = element(this.locators.layout); - public overlay: ElementFinder = element(this.locators.overlay); - snackBar: ElementFinder = browser.$(this.locators.snackBar); - dialogContainer: ElementFinder = element(this.locators.dialogContainer); - snackBarContainer: ElementFinder = browser.$(this.locators.snackBarContainer); - snackBarAction: ElementFinder = browser.$(this.locators.snackBarAction); + public app: ElementFinder = element(this.locators.app); + public layout: ElementFinder = element(this.locators.layout); + public overlay: ElementFinder = element(this.locators.overlay); + snackBar: ElementFinder = browser.$(this.locators.snackBar); + dialogContainer: ElementFinder = element(this.locators.dialogContainer); + snackBarContainer: ElementFinder = browser.$(this.locators.snackBarContainer); + snackBarAction: ElementFinder = browser.$(this.locators.snackBarAction); - genericError: ElementFinder = browser.$(this.locators.genericError); - genericErrorIcon: ElementFinder = browser.$(this.locators.genericErrorIcon); - genericErrorTitle: ElementFinder = browser.$(this.locators.genericErrorTitle); + genericError: ElementFinder = browser.$(this.locators.genericError); + genericErrorIcon: ElementFinder = browser.$(this.locators.genericErrorIcon); + genericErrorTitle: ElementFinder = browser.$(this.locators.genericErrorTitle); - constructor(public url: string = '') {} + constructor(public url: string = '') {} - get title(): promise.Promise { - return browser.getTitle(); - } + get title(): promise.Promise { + return browser.getTitle(); + } - load(relativeUrl: string = ''): promise.Promise { - const hash = Page.USE_HASH_STRATEGY ? '/#' : ''; - const path = `${hash}${this.url}${relativeUrl}`; + load(relativeUrl: string = ''): promise.Promise { + const hash = Page.USE_HASH_STRATEGY ? '/#' : ''; + const path = `${hash}${this.url}${relativeUrl}`; - return browser.get(path); - } + return browser.get(path); + } - waitForApp() { - return browser.wait(EC.presenceOf(this.layout), BROWSER_WAIT_TIMEOUT); - } + waitForApp() { + return browser.wait(EC.presenceOf(this.layout), BROWSER_WAIT_TIMEOUT); + } - waitForSnackBarToAppear() { - return browser.wait(EC.visibilityOf(this.snackBarContainer), BROWSER_WAIT_TIMEOUT); - } + waitForSnackBarToAppear() { + return browser.wait( + EC.visibilityOf(this.snackBarContainer), + BROWSER_WAIT_TIMEOUT + ); + } - waitForSnackBarToClose() { - return browser.wait(EC.not(EC.visibilityOf(this.snackBarContainer)), BROWSER_WAIT_TIMEOUT); - } + waitForSnackBarToClose() { + return browser.wait( + EC.not(EC.visibilityOf(this.snackBarContainer)), + BROWSER_WAIT_TIMEOUT + ); + } - waitForDialog() { - return browser.wait(EC.visibilityOf(this.dialogContainer), BROWSER_WAIT_TIMEOUT); - } + waitForDialog() { + return browser.wait( + EC.visibilityOf(this.dialogContainer), + BROWSER_WAIT_TIMEOUT + ); + } - waitForDialogToClose() { - return browser.wait(EC.not(EC.visibilityOf(this.dialogContainer)), BROWSER_WAIT_TIMEOUT); - } + waitForDialogToClose() { + return browser.wait( + EC.not(EC.visibilityOf(this.dialogContainer)), + BROWSER_WAIT_TIMEOUT + ); + } - refresh(): promise.Promise { - return browser.refresh(); - } + refresh(): promise.Promise { + return browser.refresh(); + } - getDialogActionByLabel(label) { - return element(by.cssContainingText('.mat-button-wrapper', label)); - } + getDialogActionByLabel(label) { + return element(by.cssContainingText('.mat-button-wrapper', label)); + } - isSnackBarDisplayed(): promise.Promise { - return this.snackBar.isDisplayed(); - } + isSnackBarDisplayed(): promise.Promise { + return this.snackBar.isDisplayed(); + } - getSnackBarMessage(): promise.Promise { - return this.waitForSnackBarToAppear() - .then(() => this.snackBar.getAttribute('innerText')); - } + getSnackBarMessage(): promise.Promise { + return this.waitForSnackBarToAppear().then(() => + this.snackBar.getAttribute('innerText') + ); + } - getSnackBarAction() { - return this.waitForSnackBarToAppear() - .then(() => this.snackBarAction); - } + getSnackBarAction() { + return this.waitForSnackBarToAppear().then(() => this.snackBarAction); + } - clickSnackBarAction() { - return this.waitForSnackBarToAppear() - .then(() => { - return browser.executeScript(function (elem) { - elem.click(); - }, this.snackBarAction); - }); - } + clickSnackBarAction() { + return this.waitForSnackBarToAppear().then(() => { + return browser.executeScript(function(elem) { + elem.click(); + }, this.snackBarAction); + }); + } - isGenericErrorDisplayed() { - return this.genericError.isDisplayed(); - } + isGenericErrorDisplayed() { + return this.genericError.isDisplayed(); + } - getGenericErrorTitle() { - return this.genericErrorTitle.getText(); - } + getGenericErrorTitle() { + return this.genericErrorTitle.getText(); + } } diff --git a/src/app/app.component.ts b/src/app/app.component.ts index c0c294199..0274342b7 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -39,7 +39,8 @@ import { SetLanguagePickerAction, SnackbarErrorAction, SetCurrentUrlAction, - SetInitialStateAction + SetInitialStateAction, + CloseModalDialogsAction } from './store/actions'; import { AppStore, @@ -47,7 +48,6 @@ import { INITIAL_APP_STATE } from './store/states/app.state'; import { filter } from 'rxjs/operators'; -import { MatDialog } from '@angular/material'; @Component({ selector: 'app-root', @@ -64,8 +64,7 @@ export class AppComponent implements OnInit { private alfrescoApiService: AlfrescoApiService, private authenticationService: AuthenticationService, private uploadService: UploadService, - private extensions: AppExtensionService, - private dialogRef: MatDialog + private extensions: AppExtensionService ) {} ngOnInit() { @@ -76,9 +75,9 @@ export class AppComponent implements OnInit { provider: 'ECM', url: this.router.url }); - this.router.navigate(['/login']); - this.dialogRef.closeAll(); + this.store.dispatch(new CloseModalDialogsAction()); + this.router.navigate(['/login']); } } }); diff --git a/src/app/material.module.ts b/src/app/material.module.ts index 9ceb1bfb3..ee901ed8d 100644 --- a/src/app/material.module.ts +++ b/src/app/material.module.ts @@ -31,7 +31,8 @@ import { MatDialogModule, MatInputModule, MatSnackBarModule, - MatProgressBarModule + MatProgressBarModule, + MAT_DIALOG_DEFAULT_OPTIONS } from '@angular/material'; @NgModule({ @@ -52,6 +53,12 @@ import { MatInputModule, MatSnackBarModule, MatProgressBarModule + ], + providers: [ + { + provide: MAT_DIALOG_DEFAULT_OPTIONS, + useValue: { closeOnNavigation: true, hasBackdrop: true } + } ] }) export class MaterialModule {} diff --git a/src/app/store/actions.ts b/src/app/store/actions.ts index e242168b6..3116ec10e 100644 --- a/src/app/store/actions.ts +++ b/src/app/store/actions.ts @@ -32,3 +32,4 @@ export * from './actions/viewer.actions'; export * from './actions/search.actions'; export * from './actions/library.actions'; export * from './actions/upload.actions'; +export * from './actions/modals.actions'; diff --git a/src/app/store/actions/modals.actions.ts b/src/app/store/actions/modals.actions.ts new file mode 100644 index 000000000..f2afcdb57 --- /dev/null +++ b/src/app/store/actions/modals.actions.ts @@ -0,0 +1,33 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Action } from '@ngrx/store'; + +export const CLOSE_MODAL_DIALOGS = 'CLOSE_MODAL_DIALOGS'; + +export class CloseModalDialogsAction implements Action { + readonly type = CLOSE_MODAL_DIALOGS; + constructor() {} +} diff --git a/src/app/store/app-store.module.ts b/src/app/store/app-store.module.ts index c753b10d0..4b43be656 100644 --- a/src/app/store/app-store.module.ts +++ b/src/app/store/app-store.module.ts @@ -40,7 +40,8 @@ import { SearchEffects, SiteEffects, UploadEffects, - FavoriteEffects + FavoriteEffects, + ModalsEffects } from './effects'; @NgModule({ @@ -56,7 +57,8 @@ import { SearchEffects, SiteEffects, UploadEffects, - FavoriteEffects + FavoriteEffects, + ModalsEffects ]), !environment.production ? StoreDevtoolsModule.instrument({ maxAge: 25 }) diff --git a/src/app/store/effects.ts b/src/app/store/effects.ts index b3e84d075..9779b7d6e 100644 --- a/src/app/store/effects.ts +++ b/src/app/store/effects.ts @@ -32,3 +32,4 @@ export * from './effects/viewer.effects'; export * from './effects/search.effects'; export * from './effects/library.effects'; export * from './effects/upload.effects'; +export * from './effects/modals.effects'; diff --git a/src/app/store/effects/modals.effects.ts b/src/app/store/effects/modals.effects.ts new file mode 100644 index 000000000..3f686d9b2 --- /dev/null +++ b/src/app/store/effects/modals.effects.ts @@ -0,0 +1,41 @@ +/*! + * @license + * Alfresco Example Content Application + * + * Copyright (C) 2005 - 2018 Alfresco Software Limited + * + * This file is part of the Alfresco Example Content Application. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * The Alfresco Example Content Application is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Alfresco Example Content Application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + */ + +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { Injectable } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { CloseModalDialogsAction, CLOSE_MODAL_DIALOGS } from '../actions'; +import { MatDialog } from '@angular/material'; + +@Injectable() +export class ModalsEffects { + constructor(private actions$: Actions, private matDialog: MatDialog) {} + + @Effect({ dispatch: false }) + closeAll$ = this.actions$.pipe( + ofType(CLOSE_MODAL_DIALOGS), + map(() => this.matDialog.closeAll()) + ); +}