Skip to content

Commit 81ac5e6

Browse files
authored
164 fix dataclone error (#165)
* fix: error handling issues * fix: error handler propogation
1 parent 169e962 commit 81ac5e6

File tree

7 files changed

+91
-43
lines changed

7 files changed

+91
-43
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"build-dev": "ng build --configuration development --aot",
5959
"test": "ng test",
6060
"lint": "ng lint",
61-
"deploy": "cd dist && scp ...",
61+
"deploy": "cd dist && scp -o \"User=neuron\" -r . wecog.research.mcgill.ca:~/tmp-frontend",
6262
"build-deploy": "npm run build && npm run sentry:generate-sourcemaps && npm run sentry:upload-sourcemaps && npm run remove-maps && npm run deploy",
6363
"lint-fix": "ng lint --fix=true",
6464
"sentry:generate-sourcemaps": "sentry-cli sourcemaps inject ./dist",

src/app/CustomErrorHandler.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { UserStateService } from './services/user-state-service';
77
import { IErrorNavigationState } from './pages/error-page/error-page.component';
88
import { HttpErrorResponse } from '@angular/common/http';
99
import { SnackbarService } from './services/snackbar/snackbar.service';
10+
import { getSafeErrorInfo } from './common/error-utils';
1011

1112
@Injectable()
1213
export default class CustomErrorHandler extends SentryErrorHandler {
@@ -35,7 +36,7 @@ export default class CustomErrorHandler extends SentryErrorHandler {
3536
state: {
3637
taskIndex: undefined,
3738
studyId: undefined,
38-
stackTrace: error.message,
39+
stackTrace: getSafeErrorInfo(error),
3940
userId: this.userStateService.currentlyLoggedInUserId,
4041
} as IErrorNavigationState,
4142
});
@@ -46,7 +47,7 @@ export default class CustomErrorHandler extends SentryErrorHandler {
4647
state: {
4748
taskIndex: this.taskManager?.currentStudyTask?.taskOrder,
4849
studyId: this.taskManager?.currentStudyTask?.studyId,
49-
stackTrace: error instanceof Error ? error.stack : error,
50+
stackTrace: getSafeErrorInfo(error),
5051
userId: this.userStateService.currentlyLoggedInUserId,
5152
} as IErrorNavigationState,
5253
});

src/app/app.module.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { LoaderComponent } from './services/loader/loader.component';
1919
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
2020
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
2121
import { HttpCsrfInterceptor } from './interceptors/csrf.interceptor';
22+
import { ErrorInterceptor } from './interceptors/error.interceptor';
2223
import { ResetPasswordLoginComponent } from './pages/landing-page/forgot-password/change-password-page/reset-password-login.component';
2324
import { SendResetPasswordComponent } from './pages/landing-page/forgot-password/send-reset-password/send-reset-password.component';
2425
import { NotFoundComponent } from './pages/landing-page/not-found/not-found.component';
@@ -82,11 +83,11 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
8283
AppRoutingModule,
8384
],
8485
providers: [
85-
// {
86-
// provide: HTTP_INTERCEPTORS,
87-
// useClass: ErrorInterceptor,
88-
// multi: true,
89-
// },
86+
{
87+
provide: HTTP_INTERCEPTORS,
88+
useClass: ErrorInterceptor,
89+
multi: true,
90+
},
9091
{
9192
provide: HTTP_INTERCEPTORS,
9293
useClass: HttpCsrfInterceptor,
@@ -96,16 +97,6 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
9697
provide: ErrorHandler,
9798
useClass: CustomErrorHandler,
9899
},
99-
// {
100-
// provide: Sentry.TraceService,
101-
// deps: [Router],
102-
// },
103-
// {
104-
// provide: APP_INITIALIZER,
105-
// useFactory: () => () => {},
106-
// deps: [Sentry.TraceService],
107-
// multi: true,
108-
// },
109100
],
110101
bootstrap: [AppComponent],
111102
})

src/app/common/error-utils.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Utility functions for safely handling errors without causing DataCloneError
3+
* when passing through Angular Router state
4+
*/
5+
6+
/**
7+
* Safely extracts error information from any type of error object
8+
* without passing non-serializable objects through router state
9+
*/
10+
export function getSafeErrorInfo(err?: any): string {
11+
let errorMessage = 'An error occurred';
12+
let errorDetails = '';
13+
14+
if (err) {
15+
if (typeof err === 'string') {
16+
errorMessage = err;
17+
} else if (err instanceof Error) {
18+
errorMessage = err.message;
19+
errorDetails = err.stack || '';
20+
} else if (err && typeof err === 'object') {
21+
// Handle HttpErrorResponse and other objects
22+
if (err.message) {
23+
errorMessage = err.message;
24+
} else if (err.error) {
25+
errorMessage = typeof err.error === 'string' ? err.error : 'HTTP Error';
26+
} else if (err.status) {
27+
errorMessage = `HTTP ${err.status}: ${err.statusText || 'Request failed'}`;
28+
}
29+
30+
// Safely extract additional details
31+
if (err.status) {
32+
errorDetails = `Status: ${err.status}`;
33+
if (err.statusText) {
34+
errorDetails += ` - ${err.statusText}`;
35+
}
36+
}
37+
}
38+
}
39+
40+
return `${errorMessage}\n${errorDetails}`.trim();
41+
}
Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,38 @@
1-
// import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
2-
// import { Injectable } from '@angular/core';
3-
// import { Router } from '@angular/router';
4-
// import { Observable, throwError } from 'rxjs';
5-
// import { catchError } from 'rxjs/operators';
6-
// import { RouteNames } from '../models/enums';
7-
// import { SnackbarService } from '../services/snackbar/snackbar.service';
1+
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
2+
import { Injectable } from '@angular/core';
3+
import { Router } from '@angular/router';
4+
import { EMPTY, Observable, of, throwError } from 'rxjs';
5+
import { catchError } from 'rxjs/operators';
6+
import { RouteNames } from '../models/enums';
7+
import { SnackbarService } from '../services/snackbar/snackbar.service';
8+
import { ClearanceService } from '../services/clearance.service';
89

9-
// @Injectable()
10-
// export class ErrorInterceptor implements HttpInterceptor {
11-
// constructor(private snackbarService: SnackbarService, private router: Router) {}
10+
@Injectable()
11+
export class ErrorInterceptor implements HttpInterceptor {
12+
constructor(
13+
private snackbarService: SnackbarService,
14+
private router: Router,
15+
private clearanceService: ClearanceService
16+
) {}
1217

13-
// intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
14-
// return next.handle(req).pipe(
15-
// catchError((err: HttpErrorResponse) => {
16-
// if (err.status === 401) {
17-
// this.snackbarService.openInfoSnackbar('Please login again to continue');
18-
// this.router.navigate([`/${RouteNames.LANDINGPAGE_LOGIN_BASEROUTE}`]);
19-
// }
20-
// return throwError(err.error);
21-
// })
22-
// );
23-
// }
24-
// }
18+
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
19+
return next.handle(req).pipe(
20+
catchError((err: HttpErrorResponse) => {
21+
if (err.status === 401) {
22+
// JWT has expired - log the user out and redirect to login
23+
this.snackbarService.openInfoSnackbar('Your session has expired. Please login again to continue.');
24+
25+
// Clear all cached data and session storage
26+
this.clearanceService.clearServices();
27+
28+
// Redirect to login page
29+
this.router.navigate([`/${RouteNames.LANDINGPAGE_LOGIN_BASEROUTE}`]);
30+
31+
// do not propagate the error to the next interceptor
32+
return EMPTY;
33+
}
34+
return throwError(err);
35+
})
36+
);
37+
}
38+
}

src/app/pages/participant/participant-dashboard/participant-studies/participant-study/participant-study.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ export class ParticipantStudyComponent implements OnInit, OnDestroy {
111111
)
112112
.subscribe(
113113
(_res) => {},
114-
(err: HttpStatus) => {
115-
this.snackbar.openErrorSnackbar(err.message);
114+
(err) => {
115+
this.taskManager.handleErr(err);
116116
}
117117
)
118118
.add(() => {

src/app/services/task-manager.service.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { UserStateService } from './user-state-service';
2525
import { CrowdSourcedUserService } from './crowdsourced-user.service';
2626
import { snapshotToStudyTasks } from './utils';
2727
import { IErrorNavigationState } from '../pages/error-page/error-page.component';
28+
import { getSafeErrorInfo } from '../common/error-utils';
2829

2930
@Injectable({
3031
providedIn: 'root',
@@ -150,7 +151,7 @@ export class TaskManagerService implements CanClear {
150151
taskIndex: this.currentStudyTask?.taskOrder,
151152
studyId: this.currentStudyTask?.studyId,
152153
userId: this.userStateService?.currentlyLoggedInUserId,
153-
stackTrace: err instanceof Error ? err.stack : err,
154+
stackTrace: getSafeErrorInfo(err),
154155
} as IErrorNavigationState,
155156
});
156157
}

0 commit comments

Comments
 (0)