Browse Source

Merge pull request #19451 from abpframework/auto-merge/rel-8-1/2613

Merge branch dev with rel-8.1
pull/19455/head
maliming 2 years ago
committed by GitHub
parent
commit
cd4a4c5691
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      npm/ng-packs/apps/dev-app/src/app/app-routing.module.ts
  2. 2
      npm/ng-packs/apps/dev-app/src/app/app.module.ts
  3. 22
      npm/ng-packs/packages/core/src/lib/services/internet-connection-service.ts
  4. 44
      npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.html
  5. 51
      npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts
  6. 83
      npm/ng-packs/packages/theme-shared/src/lib/components/internet-connection-status/internet-connection-status.component.ts
  7. 14
      npm/ng-packs/packages/theme-shared/src/lib/constants/default-errors.ts
  8. 4
      npm/ng-packs/packages/theme-shared/src/lib/constants/index.ts
  9. 17
      npm/ng-packs/packages/theme-shared/src/lib/services/create-error-component.service.ts
  10. 5
      npm/ng-packs/packages/theme-shared/src/public-api.ts
  11. 1
      templates/app-nolayers/angular/src/app/app.component.ts
  12. 3
      templates/app-nolayers/angular/src/app/app.module.ts
  13. 1
      templates/app/angular/src/app/app.component.ts
  14. 3
      templates/app/angular/src/app/app.module.ts

2
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 {}

2
npm/ng-packs/apps/dev-app/src/app/app.module.ts

@ -39,7 +39,7 @@ import { APP_ROUTE_PROVIDER } from './route.provider';
ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(),
AccountLayoutModule.forRoot(),
InternetConnectionStatusComponent
InternetConnectionStatusComponent,
],
providers: [APP_ROUTE_PROVIDER],
declarations: [AppComponent],

22
npm/ng-packs/packages/core/src/lib/services/internet-connection-service.ts

@ -5,28 +5,28 @@ import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class InternetConnectionService{
readonly document = inject(DOCUMENT)
export class InternetConnectionService {
readonly document = inject(DOCUMENT);
readonly window = this.document.defaultView;
readonly navigator = this.window.navigator;
private status$ = new BehaviorSubject<boolean>(this.navigator.onLine)
private status$ = new BehaviorSubject<boolean>(this.navigator.onLine);
private status = signal(this.navigator.onLine);
networkStatus = computed(() => this.status())
constructor(){
networkStatus = computed(() => this.status());
constructor() {
this.window.addEventListener('offline', () => this.setStatus(false));
this.window.addEventListener('online', () => this.setStatus(true));
}
setStatus(val:boolean){
this.status.set(val)
this.status$.next(val)
setStatus(val: boolean) {
this.status.set(val);
this.status$.next(val);
}
get networkStatus$(){
return this.status$.asObservable()
get networkStatus$() {
return this.status$.asObservable();
}
}

44
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"
>
<button
*ngIf="!hideCloseIcon"
id="abp-close-button"
type="button"
class="btn-close me-2"
(click)="destroy()"
></button>
@if (!hideCloseIcon) {
<button id="abp-close-button" type="button" class="btn-close me-2" (click)="destroy()"></button>
}
<div *ngIf="!customComponent" class="row centered">
<div class="col-md-12">
<div class="error-template">
<h1>{{ statusText }} {{ title | abpLocalization }}</h1>
<div class="error-details">
{{ details | abpLocalization }}
</div>
<div class="error-actions">
<a
*ngIf="isHomeShow"
(click)="destroy()"
routerLink="/"
class="btn btn-primary btn-md mt-2"
><span class="glyphicon glyphicon-home"></span>
{{ { key: '::Menu:Home', defaultValue: 'Home' } | abpLocalization }}
</a>
@if (!customComponent) {
<div class="row centered">
<div class="col-md-12">
<div class="error-template">
<h1>{{ statusText }} {{ title | abpLocalization }}</h1>
<div class="error-details">
{{ details | abpLocalization }}
</div>
<div class="error-actions">
@if (isHomeShow) {
<a (click)="goHome()" class="btn btn-primary btn-md mt-2"
><span class="glyphicon glyphicon-home"></span>
{{ { key: '::Menu:Home', defaultValue: 'Home' } | abpLocalization }}
</a>
}
</div>
</div>
</div>
</div>
</div>
}
</div>

51
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<any>).rootNodes[0],
@ -80,14 +84,17 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr
customComponentRef.changeDetectorRef.detectChanges();
}
const keyup$ = fromEvent<KeyboardEvent>(this.document, 'keyup').pipe(
debounceTime(150),
filter((key: KeyboardEvent) => key && key.key === 'Escape'),
);
this.subscription.addOne(keyup$, () => this.destroy());
fromEvent<KeyboardEvent>(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();
}
}

83
npm/ng-packs/packages/theme-shared/src/lib/components/internet-connection-status/internet-connection-status.component.ts

@ -1,47 +1,60 @@
import { Component, computed, inject } from '@angular/core';
import { NgIf } from '@angular/common'
import { InternetConnectionService , LocalizationModule } from '@abp/ng.core';
import { Component, inject } from '@angular/core';
import { InternetConnectionService, LocalizationModule } from '@abp/ng.core';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'abp-internet-status',
standalone: true,
imports:[NgIf, LocalizationModule],
imports: [LocalizationModule, NgbTooltip],
template: `
<div class="status-icon" *ngIf="!isOnline()">
<i data-toggle="tooltip" title="{{ 'AbpUi::InternetConnectionInfo' | abpLocalization }}" data-placement="left" class="fa fa-circle text-blinking blink">
</i>
</div>
`,
styles: [`
.blink {
animation: blinker 0.9s cubic-bezier(.5, 0, 1, 1) infinite alternate;
}
@keyframes blinker {
0% { color:#c1c1c1 }
70% { color: #DC3545 }
100% { color: #DC3545 }
}
.text-blinking{
font-size:1.2rem;
@if (!isOnline()) {
<div class="status-icon">
<i
ngbTooltip="{{ 'AbpUi::InternetConnectionInfo' | abpLocalization }}"
container="body"
placement="left-top"
class="fa fa-wifi text-blinking blink"
>
</i>
</div>
}
`,
styles: [
`
.blink {
animation: blinker 0.9s cubic-bezier(0.5, 0, 1, 1) infinite alternate;
}
@keyframes blinker {
0% {
color: #c1c1c1;
}
70% {
color: #fa2379;
}
100% {
color: #fa2379;
}
}
.status-icon{
position: fixed;
z-index: 999999;
top: 10px;
right: 10px;
}
.text-blinking {
font-size: 30px;
}
@media (width < 768px){
.status-icon{
top: 26px;
right: 134px;
.status-icon {
position: fixed;
z-index: 999999;
top: 50%;
left: 50%;
width: 30px;
text-align: center;
margin-left: -15px;
margin-top: -15px;
translate: transform(-50%, -50%);
}
}
`]
`,
],
})
export class InternetConnectionStatusComponent{
export class InternetConnectionStatusComponent {
internetConnectionService = inject(InternetConnectionService);
isOnline = this.internetConnectionService.networkStatus
isOnline = this.internetConnectionService.networkStatus;
}

14
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',
};

4
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';

17
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);
private readonly injector = inject(Injector);
protected readonly injector = inject(Injector);
protected readonly envInjector = inject(EnvironmentInjector);
protected readonly httpErrorConfig = inject(HTTP_ERROR_CONFIG);
componentRef: ComponentRef<HttpErrorWrapperComponent> | 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<void>();
this.componentRef.instance.destroy$ = destroy$;
destroy$.subscribe(() => {
this.componentRef?.destroy();
this.componentRef = null;

5
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';

1
templates/app-nolayers/angular/src/app/app.component.ts

@ -5,6 +5,7 @@ import { Component } from '@angular/core';
template: `
<abp-loader-bar></abp-loader-bar>
<abp-dynamic-layout></abp-dynamic-layout>
<abp-internet-status></abp-internet-status>
`,
})
export class AppComponent {}

3
templates/app-nolayers/angular/src/app/app.module.ts

@ -6,7 +6,7 @@ import { SettingManagementConfigModule } from '@abp/ng.setting-management/config
import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { InternetConnectionStatusComponent, ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -35,6 +35,7 @@ import { AbpOAuthModule } from '@abp/ng.oauth';
ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(),
FeatureManagementModule.forRoot(),
InternetConnectionStatusComponent
],
declarations: [AppComponent],
providers: [APP_ROUTE_PROVIDER],

1
templates/app/angular/src/app/app.component.ts

@ -5,6 +5,7 @@ import { Component } from '@angular/core';
template: `
<abp-loader-bar></abp-loader-bar>
<abp-dynamic-layout></abp-dynamic-layout>
<abp-internet-status></abp-internet-status>
`,
})
export class AppComponent {}

3
templates/app/angular/src/app/app.module.ts

@ -6,7 +6,7 @@ import { SettingManagementConfigModule } from '@abp/ng.setting-management/config
import { TenantManagementConfigModule } from '@abp/ng.tenant-management/config';
import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { InternetConnectionStatusComponent, ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@ -36,6 +36,7 @@ import { AccountLayoutModule } from '@abp/ng.theme.lepton-x/account';
ThemeLeptonXModule.forRoot(),
SideMenuLayoutModule.forRoot(),
FeatureManagementModule.forRoot(),
InternetConnectionStatusComponent
],
declarations: [AppComponent],
providers: [APP_ROUTE_PROVIDER],

Loading…
Cancel
Save