Add error dialog box.
- Add service for handling creation of error dialog. - Refactor directory layout.
This commit is contained in:
parent
3eaa56e0b9
commit
d76a0b3196
3
src/app/_eth/index.ts
Normal file
3
src/app/_eth/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from '@app/_eth/accountIndex';
|
||||||
|
export * from '@app/_eth/registry';
|
||||||
|
export * from '@app/_eth/token-registry';
|
@ -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', () => {
|
@ -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', () => {
|
@ -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);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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({
|
32
src/app/_interceptors/error.interceptor.ts
Normal file
32
src/app/_interceptors/error.interceptor.ts
Normal 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);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
16
src/app/_interceptors/http-config.interceptor.spec.ts
Normal file
16
src/app/_interceptors/http-config.interceptor.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
29
src/app/_interceptors/http-config.interceptor.ts
Normal file
29
src/app/_interceptors/http-config.interceptor.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
3
src/app/_interceptors/index.ts
Normal file
3
src/app/_interceptors/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from '@app/_interceptors/error.interceptor';
|
||||||
|
export * from '@app/_interceptors/http-config.interceptor';
|
||||||
|
export * from '@app/_interceptors/logging.interceptor';
|
@ -3,9 +3,10 @@ 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';
|
||||||
import {finalize, tap} from 'rxjs/operators';
|
import {finalize, tap} from 'rxjs/operators';
|
||||||
|
|
||||||
@ -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
2
src/app/_pgp/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from '@app/_pgp/pgp-key-store';
|
||||||
|
export * from '@app/_pgp/pgp-signer';
|
@ -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', () => {
|
@ -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', () => {
|
@ -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');
|
16
src/app/_services/error-dialog.service.spec.ts
Normal file
16
src/app/_services/error-dialog.service.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
33
src/app/_services/error-dialog.service.ts
Normal file
33
src/app/_services/error-dialog.service.ts
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
13
src/app/shared/error-dialog/error-dialog.component.html
Normal file
13
src/app/shared/error-dialog/error-dialog.component.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
Message: {{ data.message }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Reason: {{ data.reason }}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Status: {{ data.status }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
25
src/app/shared/error-dialog/error-dialog.component.spec.ts
Normal file
25
src/app/shared/error-dialog/error-dialog.component.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
14
src/app/shared/error-dialog/error-dialog.component.ts
Normal file
14
src/app/shared/error-dialog/error-dialog.component.ts
Normal 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) { }
|
||||||
|
|
||||||
|
}
|
@ -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,
|
||||||
@ -27,10 +30,11 @@ import {TokenRatioPipe} from '@app/shared/_pipes/token-ratio.pipe';
|
|||||||
MenuSelectionDirective,
|
MenuSelectionDirective,
|
||||||
TokenRatioPipe
|
TokenRatioPipe
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
MatIconModule
|
MatIconModule,
|
||||||
]
|
MatDialogModule,
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class SharedModule { }
|
export class SharedModule { }
|
||||||
|
Loading…
Reference in New Issue
Block a user