Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NODE_PATH=src/
SKIP_PREFLIGHT_CHECK=true
BACKEND_URL="http://localhost:8021"
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "BACKEND_URL=http://localhost:8021 react-scripts --max_old_space_size=2048 --openssl-legacy-provider start",
"start": "cross-env BACKEND_URL=http://localhost:8021 react-scripts --max_old_space_size=2048 --openssl-legacy-provider start",
"start-with-staging": "BACKEND_URL=https://staging.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start",
"start-with-prerelease": "BACKEND_URL=https://prerelease.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start",
"start-with-prod": "BACKEND_URL=https://app.avniproject.org react-scripts --max_old_space_size=2048 --openssl-legacy-provider start",
Expand Down Expand Up @@ -108,12 +108,13 @@
"not op_mini all"
],
"devDependencies": {
"@babel/runtime": "^7.22.15",
"@babel/helper-environment-visitor": "7.22.20",
"@babel/helper-string-parser": "7.22.5",
"@babel/runtime": "^7.22.15",
"@fortawesome/fontawesome-free": "^5.1.0",
"@types/jest": "^26.0.19",
"chai": "^4.2.0",
"cross-env": "^7.0.3",
"cypress": "^5.6.0",
"html-webpack-plugin": "^3.2.0",
"http-proxy-middleware": "2.0.6",
Expand Down
54 changes: 54 additions & 0 deletions src/common/utils/ErrorMessageUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,60 @@ class ErrorMessageUtil {
return { message: `${error.message}. Something went wrong please try later`, display: true };
}

// New method to get user-friendly error messages based on HTTP status codes
static getUserFriendlyErrorMessage(error) {
const status = _.get(error, "response.status") || _.get(error, "status");

// Define specific messages for common error codes
switch (status) {
case 403:
return {
message: "You don't have permission to access this resource. Please contact your administrator if you need access.",
title: "Access Denied",
display: true
};
case 404:
return {
message: "The resource you're looking for could not be found.",
title: "Not Found",
display: true
};
case 500:
return {
message: "The server encountered an error. Please try again later.",
title: "Server Error",
display: true
};
case 503:
return {
message: "The server is currently unavailable. Please try again later.",
title: "Server Unavailable",
display: true
};
default:
// Check for network errors (when server is completely unreachable)
if (
error.message &&
(error.message.includes("Network Error") ||
error.message.includes("Failed to fetch") ||
error.message.includes("ERR_CONNECTION_REFUSED"))
) {
return {
message: "Cannot connect to server. Please check your internet connection and try again.",
title: "Connection Error",
display: true
};
}

// Default fallback error message
return {
message: "An unexpected error occurred. Please try again later.",
title: "Error",
display: true
};
}
}

static fromWindowUnhandledError(error, callback) {
const unhandledError = new UnhandledRejectionError(error);
if (error.promise) {
Expand Down
23 changes: 22 additions & 1 deletion src/common/utils/httpClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import querystring from "querystring";
import IdpDetails from "../../rootApp/security/IdpDetails";
import CurrentUserService from "../service/CurrentUserService";
import _ from "lodash";
import ErrorMessageUtil from "./ErrorMessageUtil"; // Add this import Error handling

function getCsrfToken() {
// eslint-disable-next-line no-useless-escape
Expand Down Expand Up @@ -113,6 +114,15 @@ class HttpClient {
if (error.status === 401 && this.idp.idpType === IdpDetails.keycloak) {
this.idp.clearAccessToken();
}

// Use the new error handling method
const errorDetails = ErrorMessageUtil.getUserFriendlyErrorMessage(error);

// You can either handle the error display here or pass the error details up
// For now, we'll just enrich the error with our friendly message
error.friendlyMessage = errorDetails.message;
error.title = errorDetails.title;

throw error;
});
}
Expand Down Expand Up @@ -143,7 +153,18 @@ class HttpClient {
_wrapAxiosMethod(methodName) {
return async (...args) => {
await this.setTokenAndOrgUuidHeaders();
return axios[methodName](...args);
return axios[methodName](...args).catch(error => {
// Use the new error handling method
const errorDetails = ErrorMessageUtil.getUserFriendlyErrorMessage(error);

// Create an enhanced error object
const enhancedError = new Error(errorDetails.message);
enhancedError.originalError = error;
enhancedError.title = errorDetails.title;
enhancedError.display = errorDetails.display;

throw enhancedError;
});
};
}

Expand Down
27 changes: 15 additions & 12 deletions src/dataEntryApp/ErrorFallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const useStyles = makeStyles(theme => ({
border: "2px solid #d1d2d2",
borderRadius: 5,
marginTop: "10px"
},
errorTitle: {
color: "#d32f2f", // Red color for error title
marginBottom: theme.spacing(2)
}
}));

Expand Down Expand Up @@ -86,6 +90,10 @@ export function ErrorFallback({ error, onClose }) {
appHome();
};

// Get the friendly error information
const errorTitle = error.title || "Error";
const friendlyMessage = error.friendlyMessage || error.message;

return (
<div>
<AppBar className={classes.appBar}>
Expand All @@ -96,25 +104,22 @@ export function ErrorFallback({ error, onClose }) {
</Toolbar>
</AppBar>
<div className={classes.container}>
<Typography variant="h1" gutterBottom>
oops!
<Typography variant="h2" gutterBottom className={classes.errorTitle}>
{errorTitle}
</Typography>
<Typography variant="h4" gutterBottom>
There was a problem when loading this page. Please contact administrator.
<Typography variant="h5" gutterBottom>
{friendlyMessage}
</Typography>
{!showError && (
<Button onClick={() => setShowError(true)} variant={"contained"}>
Show error details
Show technical details
</Button>
)}
{showError && (
<Button
onClick={() =>
navigator.clipboard.writeText(
`Message: ${_.get(error, "message")}\n\nStack: ${_.get(
error,
"stack"
)}\n\nSaga Stack: ${_.get(error, "sagaStack")}`
`Message: ${_.get(error, "message")}\n\nStack: ${_.get(error, "stack")}\n\nSaga Stack: ${_.get(error, "sagaStack")}`
)
}
variant={"contained"}
Expand All @@ -125,9 +130,7 @@ export function ErrorFallback({ error, onClose }) {
<div style={{ display: showError ? "block" : "none" }} className={classes.errorContainer}>
<ErrorItem fieldName="Message" fieldValue={error.message} />
<ErrorItem fieldName="Error Stack" fieldValue={error.stack} />
{error["sagaStack"] && (
<ErrorItem fieldName="Saga Stack" fieldValue={error["sagaStack"]} />
)}
{error["sagaStack"] && <ErrorItem fieldName="Saga Stack" fieldValue={error["sagaStack"]} />}
</div>
<div className={classes.buttonContainer}>
<Button style={{ marginRight: 20 }} variant="contained" color="primary" onClick={appHome}>
Expand Down
Loading