From 67654d2d0c3425fa10c9935e564e734e30170865 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Apr 2020 15:06:30 +0300 Subject: [PATCH 1/3] feat(theme-shared): add an property named skipHandledErrorCodes #3636 --- .../src/lib/handlers/error.handler.ts | 29 ++++++++++++++++++- .../theme-shared/src/lib/models/common.ts | 7 ++--- .../src/lib/tokens/http-error.token.ts | 1 + 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index 93d3080cc0..82d5c44cf4 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -19,6 +19,7 @@ import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http import { HttpErrorConfig, ErrorScreenErrorCodes } from '../models/common'; import { Confirmation } from '../models/confirmation'; import { ConfirmationService } from '../services/confirmation.service'; +import { filter } from 'rxjs/operators'; export const DEFAULT_ERROR_MESSAGES = { defaultError: { @@ -58,7 +59,10 @@ export class ErrorHandler { @Inject('HTTP_ERROR_CONFIG') private httpErrorConfig: HttpErrorConfig, ) { this.actions - .pipe(ofActionSuccessful(RestOccurError, RouterError, RouterDataResolved)) + .pipe( + ofActionSuccessful(RestOccurError, RouterError, RouterDataResolved), + filter(this.filterErrors), + ) .subscribe(res => { if (res instanceof RestOccurError) { const { payload: err = {} as HttpErrorResponse | any } = res; @@ -254,4 +258,27 @@ export class ErrorHandler { this.httpErrorConfig.errorScreen.forWhichErrors.indexOf(status) > -1, ); } + + private filterErrors = ( + instance: RestOccurError | RouterError | RouterDataResolved, + ): boolean => { + if (instance instanceof RouterDataResolved) return true; + + if (instance instanceof RestOccurError) { + const { payload: err = {} as HttpErrorResponse | any } = instance; + + if (!err.status) return true; + + this.httpErrorConfig.skipHandledErrorCodes = this.httpErrorConfig.skipHandledErrorCodes || []; + + return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === err.status) < 0; + } + + if (instance instanceof RouterError) { + return ( + !snq(() => instance.event.error.indexOf('Cannot match') > -1) || + this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0 + ); + } + }; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts index 2bca410f5e..3774d97011 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts @@ -7,13 +7,10 @@ export interface RootParams { export type ErrorScreenErrorCodes = 401 | 403 | 404 | 500; export interface HttpErrorConfig { + skipHandledErrorCodes?: ErrorScreenErrorCodes[]; errorScreen?: { component: Type; - forWhichErrors?: - | [ErrorScreenErrorCodes] - | [ErrorScreenErrorCodes, ErrorScreenErrorCodes] - | [ErrorScreenErrorCodes, ErrorScreenErrorCodes, ErrorScreenErrorCodes] - | [ErrorScreenErrorCodes, ErrorScreenErrorCodes, ErrorScreenErrorCodes, ErrorScreenErrorCodes]; + forWhichErrors?: ErrorScreenErrorCodes[]; hideCloseIcon?: boolean; }; } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts b/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts index 3df2b3fe2d..62f2d2d593 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/tokens/http-error.token.ts @@ -7,6 +7,7 @@ export function httpErrorConfigFactory(config = {} as HttpErrorConfig) { } return { + skipHandledErrorCodes: [], errorScreen: {}, ...config, } as HttpErrorConfig; From 341afb26efdb1b9cd05974f137797c4dd68a6abc Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Apr 2020 15:14:58 +0300 Subject: [PATCH 2/3] feat(theme-shared): improve the skipHandledErrorCodes type --- npm/ng-packs/packages/theme-shared/src/lib/models/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts index 3774d97011..d75c854476 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/models/common.ts @@ -7,7 +7,7 @@ export interface RootParams { export type ErrorScreenErrorCodes = 401 | 403 | 404 | 500; export interface HttpErrorConfig { - skipHandledErrorCodes?: ErrorScreenErrorCodes[]; + skipHandledErrorCodes?: ErrorScreenErrorCodes[] | number[]; errorScreen?: { component: Type; forWhichErrors?: ErrorScreenErrorCodes[]; From 762546cbcbd0cbbd9edba51246086bf6553e596b Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Fri, 17 Apr 2020 16:24:14 +0300 Subject: [PATCH 3/3] refactor(theme-shared): improve error.handler readability --- .../src/lib/handlers/error.handler.ts | 232 +++++++++--------- 1 file changed, 118 insertions(+), 114 deletions(-) diff --git a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts index 82d5c44cf4..ae19f7df5e 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts @@ -19,7 +19,7 @@ import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http import { HttpErrorConfig, ErrorScreenErrorCodes } from '../models/common'; import { Confirmation } from '../models/confirmation'; import { ConfirmationService } from '../services/confirmation.service'; -import { filter } from 'rxjs/operators'; +import { filter, tap } from 'rxjs/operators'; export const DEFAULT_ERROR_MESSAGES = { defaultError: { @@ -58,111 +58,122 @@ export class ErrorHandler { private injector: Injector, @Inject('HTTP_ERROR_CONFIG') private httpErrorConfig: HttpErrorConfig, ) { + this.httpErrorConfig.skipHandledErrorCodes = this.httpErrorConfig.skipHandledErrorCodes || []; + this.listenToRestError(); + this.listenToRouterError(); + this.listenToRouterDataResolved(); + } + + private listenToRouterError() { + this.actions + .pipe(ofActionSuccessful(RouterError), filter(this.filterRouteErrors), tap(console.warn)) + .subscribe(() => this.show404Page()); + } + + private listenToRouterDataResolved() { this.actions .pipe( - ofActionSuccessful(RestOccurError, RouterError, RouterDataResolved), - filter(this.filterErrors), + ofActionSuccessful(RouterDataResolved), + filter(() => !!this.componentRef), ) - .subscribe(res => { - if (res instanceof RestOccurError) { - const { payload: err = {} as HttpErrorResponse | any } = res; - const body = snq( - () => (err as HttpErrorResponse).error.error, - DEFAULT_ERROR_MESSAGES.defaultError.title, - ); + .subscribe(() => { + this.componentRef.destroy(); + this.componentRef = null; + }); + } - if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { - const confirmation$ = this.showError(null, null, body); + private listenToRestError() { + this.actions + .pipe(ofActionSuccessful(RestOccurError), filter(this.filterRestErrors)) + .subscribe(({ payload: { err = {} as HttpErrorResponse } }) => { + const body = snq( + () => (err as HttpErrorResponse).error.error, + DEFAULT_ERROR_MESSAGES.defaultError.title, + ); - if (err.status === 401) { - confirmation$.subscribe(() => { - this.navigateToLogin(); + if (err instanceof HttpErrorResponse && err.headers.get('_AbpErrorFormat')) { + const confirmation$ = this.showError(null, null, body); + + if (err.status === 401) { + confirmation$.subscribe(() => { + this.navigateToLogin(); + }); + } + } else { + switch ((err as HttpErrorResponse).status) { + case 401: + this.canCreateCustomError(401) + ? this.show401Page() + : this.showError( + { + key: 'AbpAccount::DefaultErrorMessage401', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title, + }, + { + key: 'AbpAccount::DefaultErrorMessage401Detail', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details, + }, + ).subscribe(() => this.navigateToLogin()); + break; + case 403: + this.createErrorComponent({ + title: { + key: 'AbpAccount::DefaultErrorMessage403', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title, + }, + details: { + key: 'AbpAccount::DefaultErrorMessage403Detail', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details, + }, + status: 403, }); - } - } else { - switch ((err as HttpErrorResponse).status) { - case 401: - this.canCreateCustomError(401) - ? this.show401Page() - : this.showError( - { - key: 'AbpAccount::DefaultErrorMessage401', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title, - }, - { - key: 'AbpAccount::DefaultErrorMessage401Detail', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details, - }, - ).subscribe(() => this.navigateToLogin()); - break; - case 403: - this.createErrorComponent({ - title: { - key: 'AbpAccount::DefaultErrorMessage403', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title, - }, - details: { - key: 'AbpAccount::DefaultErrorMessage403Detail', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details, - }, - status: 403, - }); - break; - case 404: - this.canCreateCustomError(404) - ? this.show404Page() - : this.showError( - { - key: 'AbpAccount::DefaultErrorMessage404', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details, - }, - { - key: 'AbpAccount::DefaultErrorMessage404Detail', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title, - }, - ); - break; - case 500: + break; + case 404: + this.canCreateCustomError(404) + ? this.show404Page() + : this.showError( + { + key: 'AbpAccount::DefaultErrorMessage404', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details, + }, + { + key: 'AbpAccount::DefaultErrorMessage404Detail', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title, + }, + ); + break; + case 500: + this.createErrorComponent({ + title: { + key: 'AbpAccount::500Message', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title, + }, + details: { + key: 'AbpAccount::InternalServerErrorMessage', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details, + }, + status: 500, + }); + break; + case 0: + if ((err as HttpErrorResponse).statusText === 'Unknown Error') { this.createErrorComponent({ title: { - key: 'AbpAccount::500Message', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title, - }, - details: { - key: 'AbpAccount::InternalServerErrorMessage', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details, + key: 'AbpAccount::DefaultErrorMessage', + defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, }, - status: 500, + details: err.message, + isHomeShow: false, }); - break; - case 0: - if ((err as HttpErrorResponse).statusText === 'Unknown Error') { - this.createErrorComponent({ - title: { - key: 'AbpAccount::DefaultErrorMessage', - defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title, - }, - details: err.message, - isHomeShow: false, - }); - } - break; - default: - this.showError( - DEFAULT_ERROR_MESSAGES.defaultError.details, - DEFAULT_ERROR_MESSAGES.defaultError.title, - ); - break; - } + } + break; + default: + this.showError( + DEFAULT_ERROR_MESSAGES.defaultError.details, + DEFAULT_ERROR_MESSAGES.defaultError.title, + ); + break; } - } else if ( - res instanceof RouterError && - snq(() => res.event.error.indexOf('Cannot match') > -1, false) - ) { - this.show404Page(); - } else if (res instanceof RouterDataResolved && this.componentRef) { - this.componentRef.destroy(); - this.componentRef = null; } }); } @@ -259,26 +270,19 @@ export class ErrorHandler { ); } - private filterErrors = ( - instance: RestOccurError | RouterError | RouterDataResolved, - ): boolean => { - if (instance instanceof RouterDataResolved) return true; + private filterRestErrors = (instance: RestOccurError): boolean => { + const { + payload: { err: { status } = {} as HttpErrorResponse }, + } = instance; + if (!status) return false; - if (instance instanceof RestOccurError) { - const { payload: err = {} as HttpErrorResponse | any } = instance; - - if (!err.status) return true; - - this.httpErrorConfig.skipHandledErrorCodes = this.httpErrorConfig.skipHandledErrorCodes || []; - - return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === err.status) < 0; - } + return this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === status) < 0; + }; - if (instance instanceof RouterError) { - return ( - !snq(() => instance.event.error.indexOf('Cannot match') > -1) || - this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0 - ); - } + private filterRouteErrors = (instance: RouterError): boolean => { + return ( + snq(() => instance.event.error.indexOf('Cannot match') > -1) && + this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0 + ); }; }