Move constant, split error handler to little services

pull/16853/head
Mahmut Gundogdu 2 years ago
parent 6b47e1a866
commit d402ad2ea8

@ -43,3 +43,11 @@ export const DEFAULT_ERROR_LOCALIZATIONS = {
details: 'AbpUi::DefaultErrorMessage',
},
};
export const CUSTOM_HTTP_ERROR_HANDLER_PRIORITY = Object.freeze({
veryLow: -9,
low: -9,
normal: 0,
high: 9,
veryHigh: 99,
});

@ -1,68 +1,40 @@
import {
AuthService,
HttpErrorReporterService,
LocalizationParam,
RouterEvents,
SessionStateService,
} from '@abp/ng.core';
import { AuthService, HttpErrorReporterService } from '@abp/ng.core';
import { HttpErrorResponse } from '@angular/common/http';
import {
ComponentFactoryResolver,
ComponentRef,
inject,
Injectable,
Injector,
RendererFactory2,
} from '@angular/core';
import { NavigationError, ResolveEnd } from '@angular/router';
import { Observable, of, Subject, throwError } from 'rxjs';
import { inject, Injectable, Injector } from '@angular/core';
import { Observable, of, throwError } from 'rxjs';
import { catchError, filter, switchMap } from 'rxjs/operators';
import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http-error-wrapper.component';
import { ErrorScreenErrorCodes, HttpErrorConfig } from '../models/common';
import { CustomHttpErrorHandlerService, HttpErrorConfig } from '../models/common';
import { Confirmation } from '../models/confirmation';
import { ConfirmationService } from '../services/confirmation.service';
import { HTTP_ERROR_HANDLER } from '../tokens/http-error.token';
import { CUSTOM_ERROR_HANDLERS, HTTP_ERROR_HANDLER } from '../tokens/http-error.token';
import { CreateErrorComponentService } from '../services/create-error-component.service';
import { CanCreateCustomErrorService } from '../services/can-create-custom-error.service';
import { DEFAULT_ERROR_LOCALIZATIONS, DEFAULT_ERROR_MESSAGES } from '../constants/error';
import { RouterErrorHandlerService } from '../services/router-error-handler.service';
@Injectable({ providedIn: 'root' })
export class ErrorHandler {
protected httpErrorHandler = this.injector.get(HTTP_ERROR_HANDLER, (_, err: HttpErrorResponse) =>
throwError(err),
);
protected httpErrorReporter: HttpErrorReporterService;
protected routerEvents: RouterEvents;
protected confirmationService: ConfirmationService;
protected cfRes: ComponentFactoryResolver;
protected rendererFactory: RendererFactory2;
protected httpErrorConfig: HttpErrorConfig;
protected sessionStateService: SessionStateService;
private authService: AuthService;
private createErrorComponentService = inject(CreateErrorComponentService);
private canCreateCustomErrorService = inject(CanCreateCustomErrorService);
private customErrorHandlers = inject(CUSTOM_ERROR_HANDLERS);
private routerErrorHandlerService = inject(RouterErrorHandlerService);
constructor(protected injector: Injector) {
this.httpErrorReporter = injector.get(HttpErrorReporterService);
this.routerEvents = injector.get(RouterEvents);
this.confirmationService = injector.get(ConfirmationService);
this.cfRes = injector.get(ComponentFactoryResolver);
this.rendererFactory = injector.get(RendererFactory2);
this.httpErrorConfig = injector.get('HTTP_ERROR_CONFIG');
this.authService = this.injector.get(AuthService);
this.sessionStateService = this.injector.get(SessionStateService);
this.listenToRestError();
this.listenToRouterError();
}
protected listenToRouterError() {
this.routerEvents
.getNavigationEvents('Error')
.pipe(filter(this.filterRouteErrors))
.subscribe(() => this.show404Page());
this.routerErrorHandlerService.listen();
}
protected listenToRestError() {
@ -84,177 +56,45 @@ export class ErrorHandler {
);
};
private handleError(err: any) {
const body = err?.error?.error || {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
if (err instanceof HttpErrorResponse && err.headers.get('Abp-Tenant-Resolve-Error')) {
this.sessionStateService.setTenant(null)
this.authService.logout().subscribe();
return;
}
const isAbpErrorFormat = err.headers.get('_AbpErrorFormat');
if (err instanceof HttpErrorResponse && isAbpErrorFormat) {
const confirmation$ = this.showErrorWithRequestBody(body);
if (err.status === 401) {
confirmation$.subscribe(() => {
this.navigateToLogin();
});
}
} else {
switch (err.status) {
case 401:
this.canCreateCustomError(401)
? this.show401Page()
: this.showError(
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title,
},
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.details,
},
).subscribe(() => this.navigateToLogin());
break;
case 403:
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.title,
},
details: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError403.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError403.details,
},
status: 403,
});
break;
case 404:
this.canCreateCustomError(404)
? this.show404Page()
: this.showError(
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.details,
},
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title,
},
);
break;
case 500:
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.title,
},
details: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError500.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError500.details,
},
status: 500,
});
break;
case 0:
if (err.statusText === 'Unknown Error') {
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
},
details: err.message,
isHomeShow: false,
});
}
break;
default:
this.showError(
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details,
},
{
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
},
);
break;
}
}
protected sortHttpErrorHandlers(
a: CustomHttpErrorHandlerService,
b: CustomHttpErrorHandlerService,
) {
return (b.priority || 0) - (a.priority || 0);
}
protected show401Page() {
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError401.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError401.title,
},
status: 401,
});
}
protected show404Page() {
this.createErrorComponent({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title,
},
status: 404,
});
}
protected showErrorWithRequestBody(body: any) {
let message: LocalizationParam;
let title: LocalizationParam;
if (body.details) {
message = body.details;
title = body.message;
} else if (body.message) {
title = {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
message = body.message;
} else {
message = body.message || {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
title = '';
private handleError(err: unknown) {
if (this.customErrorHandlers && this.customErrorHandlers.length) {
const canHandleService = this.customErrorHandlers
.sort(this.sortHttpErrorHandlers)
.find(service => service.canHandle(err));
if (canHandleService) {
canHandleService.execute();
return;
}
}
return this.showError(message, title);
this.showError().subscribe();
}
protected showError(
message: LocalizationParam,
title: LocalizationParam,
): Observable<Confirmation.Status> {
protected showError(): Observable<Confirmation.Status> {
const title = {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
const message = {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.details,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.details,
};
return this.confirmationService.error(message, title, {
hideCancelBtn: true,
yesText: 'AbpAccount::Close',
});
}
private navigateToLogin() {
this.authService.navigateToLogin();
}
createErrorComponent(instance: Partial<HttpErrorWrapperComponent>) {
this.createErrorComponentService.execute(instance);
}
canCreateCustomError(status: ErrorScreenErrorCodes): boolean {
return this.canCreateCustomErrorService.execute(status);
}
protected filterRestErrors = ({ status }: HttpErrorResponse): boolean => {
if (typeof status !== 'number') return false;
@ -263,12 +103,4 @@ export class ErrorHandler {
this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === status) < 0
);
};
protected filterRouteErrors = (navigationError: NavigationError): boolean => {
return (
navigationError.error?.message?.indexOf('Cannot match') > -1 &&
!!this.httpErrorConfig.skipHandledErrorCodes &&
this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0
);
};
}

@ -27,3 +27,9 @@ export type HttpErrorHandler = (
) => Observable<any>;
export type LocaleDirection = 'ltr' | 'rtl';
export interface CustomHttpErrorHandlerService {
readonly priority: number;
canHandle(error: unknown): boolean;
execute();
}

@ -0,0 +1,29 @@
import { Provider } from '@angular/core';
import { CUSTOM_ERROR_HANDLERS } from '../tokens';
import { TenantResolveErrorHandlerService } from '../services/tenant-resolve-error-handler.service';
import { AbpFormatErrorHandlerService } from '../services/abp-format-error-handler.service';
import { StatusCodeErrorHandlerService } from '../services/status-code-error-handler.service';
import { UnknownStatusCodeErrorHandlerService } from '../services/unknown-status-code-error-handler.service';
export const errorHandlersProviders: Provider[] = [
{
provide: CUSTOM_ERROR_HANDLERS,
multi: true,
useClass: TenantResolveErrorHandlerService,
},
{
provide: CUSTOM_ERROR_HANDLERS,
multi: true,
useClass: AbpFormatErrorHandlerService,
},
{
provide: CUSTOM_ERROR_HANDLERS,
multi: true,
useClass: StatusCodeErrorHandlerService,
},
{
provide: CUSTOM_ERROR_HANDLERS,
multi: true,
useClass: UnknownStatusCodeErrorHandlerService,
},
];

@ -1,2 +1,3 @@
export * from './ng-bootstrap-config.provider';
export * from './route.provider';
export * from './error-handlers.provider';

@ -0,0 +1,41 @@
import { inject, Injectable } from '@angular/core';
import { AuthService } from '@abp/ng.core';
import { HttpErrorResponse } from '@angular/common/http';
import { getErrorFromRequestBody } from '../utils/error.utils';
import { CustomHttpErrorHandlerService } from '../models/common';
import { ConfirmationService } from '../services/confirmation.service';
import { CUSTOM_HTTP_ERROR_HANDLER_PRIORITY } from '../constants/error';
@Injectable({ providedIn: 'root' })
export class AbpFormatErrorHandlerService implements CustomHttpErrorHandlerService {
priority = CUSTOM_HTTP_ERROR_HANDLER_PRIORITY.high;
private confirmationService = inject(ConfirmationService);
private authService = inject(AuthService);
private error: HttpErrorResponse | undefined = undefined;
private navigateToLogin() {
return this.authService.navigateToLogin();
}
canHandle(error: unknown): boolean {
if (error instanceof HttpErrorResponse && error.headers.get('_AbpErrorFormat')) {
this.error = error;
return true;
}
return false;
}
execute() {
const { message, title } = getErrorFromRequestBody(this.error?.error?.error);
this.confirmationService
.error(message, title, {
hideCancelBtn: true,
yesText: 'AbpAccount::Close',
})
.subscribe(() => {
if (this.error?.status === 401) {
this.navigateToLogin();
}
});
}
}

@ -1,6 +1,6 @@
import { inject, Injectable } from '@angular/core';
import { ErrorScreenErrorCodes } from '../models/common';
import { HTTP_ERROR_CONFIG } from '@abp/ng.theme.shared';
import { HTTP_ERROR_CONFIG } from '../tokens/http-error.token';
@Injectable({
providedIn: 'root',

@ -8,16 +8,14 @@ import {
Injector,
RendererFactory2,
} from '@angular/core';
import {
ErrorScreenErrorCodes,
HTTP_ERROR_CONFIG,
HttpErrorWrapperComponent,
} from '@abp/ng.theme.shared';
import { Subject } from 'rxjs';
import { ResolveEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
import { RouterEvents } from '@abp/ng.core';
import { CanCreateCustomErrorService } from './can-create-custom-error.service';
import { HTTP_ERROR_CONFIG } from '../tokens/http-error.token';
import { HttpErrorWrapperComponent } from '../components/http-error-wrapper/http-error-wrapper.component';
import { ErrorScreenErrorCodes } from '../models/common';
@Injectable({ providedIn: 'root' })
export class CreateErrorComponentService {

@ -3,3 +3,10 @@ export * from './nav-items.service';
export * from './page-alert.service';
export * from './toaster.service';
export * from './user-menu.service';
export * from './can-create-custom-error.service';
export * from './create-error-component.service';
export * from './abp-format-error-handler.service';
export * from './tenant-resolve-error-handler.service';
export * from './status-code-error-handler.service';
export * from './unknown-status-code-error-handler.service';
export * from './router-error-handler.service';

@ -0,0 +1,41 @@
import { inject, Injectable } from '@angular/core';
import { filter } from 'rxjs/operators';
import { RouterEvents } from '@abp/ng.core';
import { NavigationError } from '@angular/router';
import { HTTP_ERROR_CONFIG } from '../tokens/';
import { CreateErrorComponentService } from '../services';
import { DEFAULT_ERROR_LOCALIZATIONS, DEFAULT_ERROR_MESSAGES } from '../constants/error';
@Injectable({ providedIn: 'root' })
export class RouterErrorHandlerService {
private readonly routerEvents = inject(RouterEvents);
private httpErrorConfig = inject(HTTP_ERROR_CONFIG);
private createErrorComponentService = inject(CreateErrorComponentService);
listen() {
this.routerEvents
.getNavigationEvents('Error')
.pipe(filter(this.filterRouteErrors))
.subscribe(() => this.show404Page());
}
protected filterRouteErrors = (navigationError: NavigationError): boolean => {
return (
navigationError.error?.message?.indexOf('Cannot match') > -1 &&
!!this.httpErrorConfig.skipHandledErrorCodes &&
this.httpErrorConfig.skipHandledErrorCodes.findIndex(code => code === 404) < 0
);
};
show404Page() {
const instance = {
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError404.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError404.title,
},
status: 404,
};
this.createErrorComponentService.execute(instance);
}
}

@ -0,0 +1,102 @@
import { Confirmation, CustomHttpErrorHandlerService } from '../models';
import {
CUSTOM_HTTP_ERROR_HANDLER_PRIORITY,
DEFAULT_ERROR_LOCALIZATIONS,
DEFAULT_ERROR_MESSAGES,
} from '../constants/error';
import { AuthService, LocalizationParam } from '@abp/ng.core';
import { Observable } from 'rxjs';
import { inject, Injectable } from '@angular/core';
import { ConfirmationService } from './confirmation.service';
import { CanCreateCustomErrorService } from './can-create-custom-error.service';
import { CreateErrorComponentService } from './create-error-component.service';
@Injectable({ providedIn: 'root' })
export class StatusCodeErrorHandlerService implements CustomHttpErrorHandlerService {
private readonly confirmationService = inject(ConfirmationService);
private readonly canCreateCustomErrorService = inject(CanCreateCustomErrorService);
private readonly createErrorComponentService = inject(CreateErrorComponentService);
private readonly authService = inject(AuthService);
readonly priority = CUSTOM_HTTP_ERROR_HANDLER_PRIORITY.normal;
private status: typeof this.handledStatusCodes[number];
private readonly handledStatusCodes = [401, 403, 404, 500] as const;
canHandle({ status }): boolean {
this.status = status;
return this.handledStatusCodes.indexOf(status) > -1;
}
execute() {
const key = `defaultError${this.status}`;
const title = {
key: DEFAULT_ERROR_LOCALIZATIONS[key]?.title,
defaultValue: DEFAULT_ERROR_MESSAGES[key]?.title,
};
const message = {
key: DEFAULT_ERROR_LOCALIZATIONS[key]?.details,
defaultValue: DEFAULT_ERROR_MESSAGES[key]?.details,
};
const canCreateCustomError = this.canCreateCustomErrorService.execute(this.status);
switch (this.status) {
case 401:
if (canCreateCustomError) {
this.showPage();
} else {
this.showConfirmation(title, message).subscribe(() => this.navigateToLogin());
}
break;
case 403:
this.showPage();
break;
case 404:
if (canCreateCustomError) {
this.showPage();
} else {
this.showConfirmation(title, message).subscribe();
}
break;
case 500:
this.showPage();
break;
}
}
private navigateToLogin() {
this.authService.navigateToLogin();
}
protected showConfirmation(
message: LocalizationParam,
title: LocalizationParam,
): Observable<Confirmation.Status> {
return this.confirmationService.error(message, title, {
hideCancelBtn: true,
yesText: 'AbpAccount::Close',
});
}
protected showPage() {
const key = `defaultError${this.status}`;
const instance = {
title: {
key: DEFAULT_ERROR_LOCALIZATIONS[key]?.title,
defaultValue: DEFAULT_ERROR_MESSAGES[key]?.title,
},
details: {
key: DEFAULT_ERROR_LOCALIZATIONS[key]?.details,
defaultValue: DEFAULT_ERROR_MESSAGES[key]?.details,
},
status: this.status,
};
const shouldRemoveDetail = [401, 404].indexOf(this.status) > -1;
if (shouldRemoveDetail) {
delete instance.details;
}
this.createErrorComponentService.execute(instance);
}
}

@ -0,0 +1,22 @@
import { CustomHttpErrorHandlerService } from '../models/common';
import { inject, Injectable } from '@angular/core';
import { AuthService } from '@abp/ng.core';
import { HttpErrorResponse } from '@angular/common/http';
import { CUSTOM_HTTP_ERROR_HANDLER_PRIORITY } from '../constants/error';
@Injectable({ providedIn: 'root' })
export class TenantResolveErrorHandlerService implements CustomHttpErrorHandlerService {
priority = CUSTOM_HTTP_ERROR_HANDLER_PRIORITY.high;
private authService = inject(AuthService);
private isTenantResolveError(error: unknown) {
return error instanceof HttpErrorResponse && !!error.headers.get('Abp-Tenant-Resolve-Error');
}
canHandle(error: unknown): boolean {
return this.isTenantResolveError(error);
}
execute() {
this.authService.logout().subscribe();
}
}

@ -0,0 +1,35 @@
import { CustomHttpErrorHandlerService } from '../models';
import {
CUSTOM_HTTP_ERROR_HANDLER_PRIORITY,
DEFAULT_ERROR_LOCALIZATIONS,
DEFAULT_ERROR_MESSAGES,
} from '../constants/error';
import { inject, Injectable } from '@angular/core';
import { CreateErrorComponentService } from './create-error-component.service';
@Injectable({ providedIn: 'root' })
export class UnknownStatusCodeErrorHandlerService implements CustomHttpErrorHandlerService {
priority = CUSTOM_HTTP_ERROR_HANDLER_PRIORITY.normal;
private statusText = 'Unknown Error';
private message = '';
private createErrorComponentService = inject(CreateErrorComponentService);
canHandle(error: { status: number; statusText: string; message: string } | undefined): boolean {
if (error && error.status === 0 && error.statusText === this.statusText) {
this.message = error.message;
return true;
}
return false;
}
execute() {
this.createErrorComponentService.execute({
title: {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
},
details: this.message,
isHomeShow: false,
});
}
}

@ -29,7 +29,7 @@ import { NgxDatatableListDirective } from './directives/ngx-datatable-list.direc
import { DocumentDirHandlerService } from './handlers/document-dir.handler';
import { ErrorHandler } from './handlers/error.handler';
import { RootParams } from './models/common';
import { NG_BOOTSTRAP_CONFIG_PROVIDERS } from './providers';
import { errorHandlersProviders, NG_BOOTSTRAP_CONFIG_PROVIDERS } from './providers';
import { THEME_SHARED_ROUTE_PROVIDERS } from './providers/route.provider';
import { THEME_SHARED_APPEND_CONTENT } from './tokens/append-content.token';
import { HTTP_ERROR_CONFIG, httpErrorConfigFactory } from './tokens/http-error.token';
@ -58,7 +58,7 @@ const declarationsWithExports = [
ModalCloseDirective,
AbpVisibleDirective,
FormInputComponent,
FormCheckboxComponent
FormCheckboxComponent,
];
@NgModule({
@ -69,7 +69,6 @@ const declarationsWithExports = [
NgbPaginationModule,
EllipsisModule,
CardModule,
],
declarations: [...declarationsWithExports, HttpErrorWrapperComponent],
exports: [
@ -77,11 +76,11 @@ const declarationsWithExports = [
EllipsisModule,
NgxValidateCoreModule,
CardModule,
...declarationsWithExports
...declarationsWithExports,
],
providers: [DatePipe],
})
export class BaseThemeSharedModule { }
export class BaseThemeSharedModule {}
@NgModule({
imports: [BaseThemeSharedModule],
@ -144,6 +143,7 @@ export class ThemeSharedModule {
...(confirmationIcons || {}),
},
},
errorHandlersProviders,
],
};
}

@ -1,5 +1,5 @@
import { InjectionToken } from '@angular/core';
import { HttpErrorConfig, HttpErrorHandler } from '../models/common';
import { CustomHttpErrorHandlerService, HttpErrorConfig, HttpErrorHandler } from '../models/common';
export function httpErrorConfigFactory(config = {} as HttpErrorConfig) {
if (config.errorScreen && config.errorScreen.component && !config.errorScreen.forWhichErrors) {
@ -16,3 +16,7 @@ export function httpErrorConfigFactory(config = {} as HttpErrorConfig) {
export const HTTP_ERROR_CONFIG = new InjectionToken<HttpErrorConfig>('HTTP_ERROR_CONFIG');
export const HTTP_ERROR_HANDLER = new InjectionToken<HttpErrorHandler>('HTTP_ERROR_HANDLER');
export const CUSTOM_ERROR_HANDLERS = new InjectionToken<CustomHttpErrorHandlerService[]>(
'CUSTOM_ERROR_HANDLERS',
);

@ -0,0 +1,26 @@
import { LocalizationParam } from '@abp/ng.core';
import { DEFAULT_ERROR_LOCALIZATIONS, DEFAULT_ERROR_MESSAGES } from '../constants/error';
export function getErrorFromRequestBody(body: { details?: string; message?: string } | undefined) {
let message: LocalizationParam;
let title: LocalizationParam;
if (body.details) {
message = body.details;
title = body.message;
} else if (body.message) {
title = {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
message = body.message;
} else {
message = {
key: DEFAULT_ERROR_LOCALIZATIONS.defaultError.title,
defaultValue: DEFAULT_ERROR_MESSAGES.defaultError.title,
};
title = '';
}
return { message, title };
}

@ -1,2 +1,3 @@
export * from './date-parser-formatter';
export * from './validation-utils';
export * from './error.utils';

Loading…
Cancel
Save