diff --git a/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts b/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts index 6588538b28..0d9f82ea25 100644 --- a/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts +++ b/npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts @@ -31,4 +31,4 @@ const routes: Routes = [ imports: [RouterModule.forRoot(routes, {})], exports: [RouterModule], }) -export class AppRoutingModule { } +export class AppRoutingModule {} diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.html b/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.html index cb3adb0e17..f2a887da85 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.html +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.html @@ -4,32 +4,28 @@ class="error" [style.backgroundColor]="backgroundColor" > - + @if (!hideCloseIcon) { + + } -
-
-
-

{{ statusText }} {{ title | abpLocalization }}

-
- {{ details | abpLocalization }} -
-
- - {{ { key: '::Menu:Home', defaultValue: 'Home' } | abpLocalization }} - + @if (!customComponent) { +
+
+
+

{{ statusText }} {{ title | abpLocalization }}

+
+ {{ details | abpLocalization }} +
+
-
+ }
diff --git a/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts b/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts index 7761751e8c..83002a3a88 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts @@ -1,38 +1,40 @@ import { ApplicationRef, Component, - Injector, inject, OnInit, - ComponentFactoryResolver, ElementRef, EmbeddedViewRef, Type, ViewChild, AfterViewInit, OnDestroy, + createComponent, + EnvironmentInjector, + DestroyRef, } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DOCUMENT } from '@angular/common'; +import { Router } from '@angular/router'; import { fromEvent, Subject } from 'rxjs'; import { debounceTime, filter } from 'rxjs/operators'; -import { LocalizationParam, SubscriptionService } from '@abp/ng.core'; +import { LocalizationParam } from '@abp/ng.core'; import { ErrorScreenErrorCodes } from '../../models'; @Component({ selector: 'abp-http-error-wrapper', templateUrl: './http-error-wrapper.component.html', styleUrls: ['http-error-wrapper.component.scss'], - providers: [SubscriptionService], }) export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestroy { + protected readonly destroyRef = inject(DestroyRef); protected readonly document = inject(DOCUMENT); protected readonly window = this.document.defaultView; + protected readonly router = inject(Router); appRef!: ApplicationRef; - cfRes!: ComponentFactoryResolver; - - injector!: Injector; + environmentInjector!: EnvironmentInjector; status: ErrorScreenErrorCodes = 0; @@ -57,21 +59,23 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr return this.status ? `[${this.status}]` : ''; } - constructor(private subscription: SubscriptionService) {} - ngOnInit(): void { - this.backgroundColor = - this.window.getComputedStyle(this.document.body)?.getPropertyValue('background-color') || '#fff'; + const computedStyle = this.window.getComputedStyle(this.document.body); + const backgroundColor = computedStyle?.getPropertyValue('background-color'); + this.backgroundColor = backgroundColor || '#fff'; } ngAfterViewInit(): void { if (this.customComponent) { - const customComponentRef = this.cfRes - .resolveComponentFactory(this.customComponent) - .create(this.injector); + const customComponentRef = createComponent(this.customComponent, { + environmentInjector: this.environmentInjector, + }); + customComponentRef.instance.errorStatus = this.status; customComponentRef.instance.destroy$ = this.destroy$; + this.appRef.attachView(customComponentRef.hostView); + if (this.containerRef) { this.containerRef.nativeElement.appendChild( (customComponentRef.hostView as EmbeddedViewRef).rootNodes[0], @@ -80,14 +84,17 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr customComponentRef.changeDetectorRef.detectChanges(); } - const keyup$ = fromEvent(this.document, 'keyup').pipe( - debounceTime(150), - filter((key: KeyboardEvent) => key && key.key === 'Escape'), - ); - this.subscription.addOne(keyup$, () => this.destroy()); + fromEvent(this.document, 'keyup') + .pipe( + debounceTime(150), + filter((key: KeyboardEvent) => key && key.key === 'Escape'), + takeUntilDestroyed(this.destroyRef), + ) + .subscribe(() => this.destroy()); } - ngOnDestroy(): void { + goHome(): void { + this.router.navigateByUrl('/', { onSameUrlNavigation: 'reload' }); this.destroy(); } @@ -95,4 +102,8 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr this.destroy$.next(); this.destroy$.complete(); } + + ngOnDestroy(): void { + this.destroy(); + } } diff --git a/npm/ng-packs/packages/theme-shared/src/lib/constants/default-errors.ts b/npm/ng-packs/packages/theme-shared/src/lib/constants/default-errors.ts index 46a0605b95..6a2797e037 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/constants/default-errors.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/constants/default-errors.ts @@ -51,3 +51,17 @@ export const CUSTOM_HTTP_ERROR_HANDLER_PRIORITY = Object.freeze({ high: 9, veryHigh: 99, }); + +export const HTTP_ERROR_STATUS = { + '401': 'AbpUi::401Message', + '403': 'AbpUi::403Message', + '404': 'AbpUi::404Message', + '500': 'AbpUi::500Message', +}; + +export const HTTP_ERROR_DETAIL = { + '401': 'AbpUi::DefaultErrorMessage401Detail', + '403': 'AbpUi::DefaultErrorMessage403Detail', + '404': 'AbpUi::DefaultErrorMessage404Detail', + '500': 'AbpUi::DefaultErrorMessage', +}; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/constants/index.ts b/npm/ng-packs/packages/theme-shared/src/lib/constants/index.ts new file mode 100644 index 0000000000..d08eba52b8 --- /dev/null +++ b/npm/ng-packs/packages/theme-shared/src/lib/constants/index.ts @@ -0,0 +1,4 @@ +export * from './validation'; +export * from './default-errors'; +export * from './styles'; +export * from './scripts'; diff --git a/npm/ng-packs/packages/theme-shared/src/lib/services/create-error-component.service.ts b/npm/ng-packs/packages/theme-shared/src/lib/services/create-error-component.service.ts index 5a6f02aef9..92bafb840c 100644 --- a/npm/ng-packs/packages/theme-shared/src/lib/services/create-error-component.service.ts +++ b/npm/ng-packs/packages/theme-shared/src/lib/services/create-error-component.service.ts @@ -1,8 +1,9 @@ import { ApplicationRef, - ComponentFactoryResolver, ComponentRef, + createComponent, EmbeddedViewRef, + EnvironmentInjector, inject, Injectable, Injector, @@ -21,9 +22,9 @@ import { ErrorScreenErrorCodes } from '../models/common'; export class CreateErrorComponentService { protected readonly document = inject(DOCUMENT); protected readonly rendererFactory = inject(RendererFactory2); - protected readonly cfRes = inject(ComponentFactoryResolver); protected readonly routerEvents = inject(RouterEvents); protected readonly injector = inject(Injector); + protected readonly envInjector = inject(EnvironmentInjector); protected readonly httpErrorConfig = inject(HTTP_ERROR_CONFIG); componentRef: ComponentRef | null = null; @@ -65,9 +66,9 @@ export class CreateErrorComponentService { const hostElement = this.getErrorHostElement(); const host = renderer.selectRootElement(hostElement, true); - this.componentRef = this.cfRes - .resolveComponentFactory(HttpErrorWrapperComponent) - .create(this.injector); + this.componentRef = createComponent(HttpErrorWrapperComponent, { + environmentInjector: this.envInjector, + }); for (const key in instance) { /* istanbul ignore else */ @@ -80,9 +81,8 @@ export class CreateErrorComponentService { const appRef = this.injector.get(ApplicationRef); if (this.canCreateCustomError(instance.status as ErrorScreenErrorCodes)) { - this.componentRef.instance.cfRes = this.cfRes; this.componentRef.instance.appRef = appRef; - this.componentRef.instance.injector = this.injector; + this.componentRef.instance.environmentInjector = this.envInjector; this.componentRef.instance.customComponent = this.httpErrorConfig.errorScreen?.component; } @@ -91,6 +91,7 @@ export class CreateErrorComponentService { const destroy$ = new Subject(); this.componentRef.instance.destroy$ = destroy$; + destroy$.subscribe(() => { this.componentRef?.destroy(); this.componentRef = null; diff --git a/npm/ng-packs/packages/theme-shared/src/public-api.ts b/npm/ng-packs/packages/theme-shared/src/public-api.ts index 659e59e490..43411c916d 100644 --- a/npm/ng-packs/packages/theme-shared/src/public-api.ts +++ b/npm/ng-packs/packages/theme-shared/src/public-api.ts @@ -2,11 +2,9 @@ * Public API Surface of theme-shared */ -export * from './lib/adapters' +export * from './lib/adapters'; export * from './lib/animations'; export * from './lib/components'; -export * from './lib/constants/validation'; -export * from './lib/constants/default-errors'; export * from './lib/directives'; export * from './lib/enums'; export * from './lib/handlers'; @@ -16,3 +14,4 @@ export * from './lib/services'; export * from './lib/theme-shared.module'; export * from './lib/tokens'; export * from './lib/utils'; +export * from './lib/constants';