Add error dialog box.

- Add service for handling creation of error dialog.
- Refactor directory layout.
This commit is contained in:
Spencer Ofwiti 2021-03-15 14:54:46 +03:00
parent 3eaa56e0b9
commit d76a0b3196
26 changed files with 209 additions and 42 deletions

3
src/app/_eth/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from '@app/_eth/accountIndex';
export * from '@app/_eth/registry';
export * from '@app/_eth/token-registry';

View File

@ -1,4 +1,4 @@
import { Registry } from '@app/_helpers/registry'; import { Registry } from '@app/_eth/registry';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
describe('Registry', () => { describe('Registry', () => {

View File

@ -1,4 +1,4 @@
import { TokenRegistry } from '@app/_helpers/token-registry'; import { TokenRegistry } from '@app/_eth/token-registry';
import {environment} from '@src/environments/environment'; import {environment} from '@src/environments/environment';
describe('TokenRegistry', () => { describe('TokenRegistry', () => {

View File

@ -1,25 +0,0 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError} from 'rxjs/operators';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(catchError(err => {
if ([401, 403].indexOf(err.status) !== -1) {
location.reload(true);
}
const error = err.error.message || err.statusText;
return throwError(error);
}));
}
}

View File

@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing'; import { TestBed } from '@angular/core/testing';
import { ErrorInterceptor } from '@app/_helpers/error.interceptor'; import { ErrorInterceptor } from '@app/_interceptors/error.interceptor';
describe('ErrorInterceptor', () => { describe('ErrorInterceptor', () => {
beforeEach(() => TestBed.configureTestingModule({ beforeEach(() => TestBed.configureTestingModule({

View File

@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor, HttpErrorResponse
} from '@angular/common/http';
import {Observable, throwError} from 'rxjs';
import {catchError} from 'rxjs/operators';
import {ErrorDialogService} from '@app/_services';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private errorDialogService: ErrorDialogService) {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
return next.handle(request).pipe(catchError((err: HttpErrorResponse) => {
const data = {
message: err.error.message || err.statusText,
reason: err && err.error && err.error.reason ? err.error.reason : '',
status: err.status
};
this.errorDialogService.openDialog(data);
if ([401, 403].indexOf(err.status) !== -1) {
location.reload(true);
}
// const error = err.error.message || err.statusText;
return throwError(err);
}));
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { HttpConfigInterceptor } from './http-config.interceptor';
describe('HttpConfigInterceptor', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [
HttpConfigInterceptor
]
}));
it('should be created', () => {
const interceptor: HttpConfigInterceptor = TestBed.inject(HttpConfigInterceptor);
expect(interceptor).toBeTruthy();
});
});

View File

@ -0,0 +1,29 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {
constructor() {}
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
const token = sessionStorage.getItem(btoa('CICADA_SESSION_TOKEN'));
if (token) {
request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)});
}
if (!request.headers.has('Content-Type')) {
request = request.clone({headers: request.headers.set('Content-Type', 'application/json')});
}
request = request.clone({headers: request.headers.set('Accept', 'application/json')});
return next.handle(request);
}
}

View File

@ -0,0 +1,3 @@
export * from '@app/_interceptors/error.interceptor';
export * from '@app/_interceptors/http-config.interceptor';
export * from '@app/_interceptors/logging.interceptor';

View File

@ -3,7 +3,8 @@ import {
HttpRequest, HttpRequest,
HttpHandler, HttpHandler,
HttpEvent, HttpEvent,
HttpInterceptor, HttpResponse HttpInterceptor,
HttpResponse
} from '@angular/common/http'; } from '@angular/common/http';
import {Observable} from 'rxjs'; import {Observable} from 'rxjs';
import {LoggingService} from '@app/_services/logging.service'; import {LoggingService} from '@app/_services/logging.service';
@ -26,9 +27,10 @@ export class LoggingInterceptor implements HttpInterceptor {
if (event instanceof HttpResponse) { if (event instanceof HttpResponse) {
status = 'succeeded'; status = 'succeeded';
} }
}, error => status = 'failed'), finalize(() => { }, error => status = 'failed'),
finalize(() => {
const elapsedTime = Date.now() - startTime; const elapsedTime = Date.now() - startTime;
const message = `${request.method} ${request.urlWithParams} ${status} in ${elapsedTime} ms`; const message = `${request.method} request for ${request.urlWithParams} ${status} in ${elapsedTime} ms`;
this.loggingService.sendInfoLevelMessage(message); this.loggingService.sendInfoLevelMessage(message);
})); }));
} }

2
src/app/_pgp/index.ts Normal file
View File

@ -0,0 +1,2 @@
export * from '@app/_pgp/pgp-key-store';
export * from '@app/_pgp/pgp-signer';

View File

@ -1,4 +1,4 @@
import { MutablePgpKeyStore } from '@app/_helpers/pgp-key-store'; import { MutablePgpKeyStore } from '@app/_pgp/pgp-key-store';
describe('PgpKeyStore', () => { describe('PgpKeyStore', () => {
it('should create an instance', () => { it('should create an instance', () => {

View File

@ -1,5 +1,5 @@
import { PGPSigner } from '@app/_helpers/pgp-signer'; import { PGPSigner } from '@app/_pgp/pgp-signer';
import {MutableKeyStore, MutablePgpKeyStore} from '@app/_helpers/pgp-key-store'; import {MutableKeyStore, MutablePgpKeyStore} from '@app/_pgp/pgp-key-store';
const keystore: MutableKeyStore = new MutablePgpKeyStore(); const keystore: MutableKeyStore = new MutablePgpKeyStore();
describe('PgpSigner', () => { describe('PgpSigner', () => {

View File

@ -1,4 +1,4 @@
import {MutableKeyStore} from '@app/_helpers/pgp-key-store'; import {MutableKeyStore} from '@app/_pgp/pgp-key-store';
import {LoggingService} from '@app/_services/logging.service'; import {LoggingService} from '@app/_services/logging.service';
const openpgp = require('openpgp'); const openpgp = require('openpgp');

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { ErrorDialogService } from './error-dialog.service';
describe('ErrorDialogService', () => {
let service: ErrorDialogService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(ErrorDialogService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import {MatDialog} from '@angular/material/dialog';
import {ErrorDialogComponent} from '@app/shared/error-dialog/error-dialog.component';
import {LoggingService} from '@app/_services/logging.service';
@Injectable({
providedIn: 'root'
})
export class ErrorDialogService {
public isDialogOpen: boolean = false;
constructor(
public dialog: MatDialog,
private loggingService: LoggingService
) { }
openDialog(data): any {
if (this.isDialogOpen) {
return false;
}
this.isDialogOpen = true;
const dialogRef = this.dialog.open(ErrorDialogComponent, {
width: '300px',
data
});
dialogRef.afterClosed().subscribe(result => {
this.loggingService.sendInfoLevelMessage('The dialog was closed');
this.isDialogOpen = false;
const res = result;
});
}
}

View File

@ -0,0 +1,13 @@
<div>
<div>
<p>
Message: {{ data.message }}
</p>
<p>
Reason: {{ data.reason }}
</p>
<p>
Status: {{ data.status }}
</p>
</div>
</div>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorDialogComponent } from './error-dialog.component';
describe('ErrorDialogComponent', () => {
let component: ErrorDialogComponent;
let fixture: ComponentFixture<ErrorDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ErrorDialogComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ErrorDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,14 @@
import {Component, ChangeDetectionStrategy, Inject} from '@angular/core';
import {MAT_DIALOG_DATA} from '@angular/material/dialog';
@Component({
selector: 'app-error-dialog',
templateUrl: './error-dialog.component.html',
styleUrls: ['./error-dialog.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ErrorDialogComponent {
constructor(@Inject(MAT_DIALOG_DATA) public data: string) { }
}

View File

@ -8,6 +8,8 @@ import { MenuToggleDirective } from '@app/shared/_directives/menu-toggle.directi
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {MatIconModule} from '@angular/material/icon'; import {MatIconModule} from '@angular/material/icon';
import {TokenRatioPipe} from '@app/shared/_pipes/token-ratio.pipe'; import {TokenRatioPipe} from '@app/shared/_pipes/token-ratio.pipe';
import { ErrorDialogComponent } from './error-dialog/error-dialog.component';
import {MatDialogModule} from '@angular/material/dialog';
@ -18,7 +20,8 @@ import {TokenRatioPipe} from '@app/shared/_pipes/token-ratio.pipe';
SidebarComponent, SidebarComponent,
MenuSelectionDirective, MenuSelectionDirective,
MenuToggleDirective, MenuToggleDirective,
TokenRatioPipe TokenRatioPipe,
ErrorDialogComponent
], ],
exports: [ exports: [
TopbarComponent, TopbarComponent,
@ -30,7 +33,8 @@ import {TokenRatioPipe} from '@app/shared/_pipes/token-ratio.pipe';
imports: [ imports: [
CommonModule, CommonModule,
RouterModule, RouterModule,
MatIconModule MatIconModule,
MatDialogModule,
] ]
}) })
export class SharedModule { } export class SharedModule { }