This commit is contained in:
230
client/src/api/errorhandler.js
Normal file
230
client/src/api/errorhandler.js
Normal file
@@ -0,0 +1,230 @@
|
||||
let lastMessageHash = 0;
|
||||
let lastMessageTimeStamp = new Date();
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// translate, Log and optionally display errors
|
||||
// return translated message in case caller needs it
|
||||
async function dealWithError(msg, vm) {
|
||||
//Check if this is the same message again as last time within a short time span to avoid endless looping errors of same message
|
||||
//but still allow for user to repeat operation that causes error so they can view it
|
||||
const newHash = window.$gz.util.quickHash(msg);
|
||||
if (newHash == lastMessageHash) {
|
||||
const tsnow = new Date();
|
||||
//don't show the same exact message if it was just shown less than 1 second ago
|
||||
if (tsnow - lastMessageTimeStamp < 1000) return;
|
||||
}
|
||||
lastMessageHash = newHash;
|
||||
lastMessageTimeStamp = new Date();
|
||||
|
||||
//translate as necessary
|
||||
msg = await window.$gz.translation.translateStringWithMultipleKeysAsync(msg);
|
||||
|
||||
//In some cases the error may not be translatable, if this is not a debug run then it should show without the ?? that translating puts in keys not found
|
||||
//so it's not as weird looking to the user
|
||||
//vm may be null here so check window gz for dev
|
||||
if (!window.$gz.dev && msg.includes("??")) {
|
||||
msg = msg.replace("??", "");
|
||||
}
|
||||
window.$gz.store.commit("logItem", msg);
|
||||
if (window.$gz.dev) {
|
||||
const errMsg = "DEV MODE errorHandler.js:: Unexpected error: \r\n" + msg;
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(errMsg);
|
||||
|
||||
// eslint-disable-next-line no-debugger
|
||||
debugger;
|
||||
}
|
||||
|
||||
//If a form instance was provided (vue instance)
|
||||
//and it can display and error then put the error into it
|
||||
if (!vm || vm.formState == undefined) {
|
||||
//Special work around to not redundantly display errors when Sockeye job fails
|
||||
// and Vue decides to throw it's own error into the mix when we've already displayed appropriate message
|
||||
if (msg.includes("Vue error") && msg.includes("Job failed")) {
|
||||
return;
|
||||
}
|
||||
|
||||
//popup if no place to display it elsewise
|
||||
window.$gz.eventBus.$emit("notify-error", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
//should be able to display in form...
|
||||
if (vm.$sock.dev) {
|
||||
//make sure formState.appError is defined on data
|
||||
if (!window.$gz.util.has(vm, "formState.appError")) {
|
||||
throw new Error(
|
||||
"DEV ERROR errorHandler::dealWithError -> formState.appError seems to be missing from form's vue data object"
|
||||
);
|
||||
}
|
||||
}
|
||||
vm.formState.appError = msg;
|
||||
|
||||
//TODO: What is this doing exactly?
|
||||
//it's related to server errors but I'm setting appError above
|
||||
//why two error properties?
|
||||
window.$gz.form.setErrorBoxErrors(vm);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// DECODE ERROR TO TEXT
|
||||
// accept an unknown type of error variable
|
||||
// and return human readable text
|
||||
//
|
||||
function decodeError(e, vm) {
|
||||
// console.log("decodeError full e object as is: ");
|
||||
// console.log(e);
|
||||
// console.log("decodeError full e object stringified: ", JSON.stringify(e));
|
||||
// console.log("decodeError is typeof:", typeof e);
|
||||
// console.log("decodeError e is instanceof Error ", e instanceof Error);
|
||||
// console.log(
|
||||
// "decodeError e is a string already: ",
|
||||
// window.$gz.util.isString(e)
|
||||
// );
|
||||
|
||||
//already a string?
|
||||
if (window.$gz.util.isString(e)) {
|
||||
return e; //nothing to do here, already a string
|
||||
}
|
||||
|
||||
if (e instanceof Error) {
|
||||
//an Error object?
|
||||
return `Error - Name:${e.name}, Message:${e.message}`;
|
||||
}
|
||||
|
||||
if (
|
||||
e == null ||
|
||||
e == "" ||
|
||||
(typeof e === "object" && Object.keys(e).length === 0)
|
||||
) {
|
||||
return `errorHandler::decodeError - Error is unknown / empty (e:${e})`;
|
||||
}
|
||||
|
||||
//API error object or error RESPONSE object?
|
||||
if (e.error || e.code) {
|
||||
let err = null;
|
||||
//could be the error RESPONSE or it could be the error object *inside* the error response so sort out here
|
||||
if (e.error) {
|
||||
//it's the entire resopnse object
|
||||
err = e.error;
|
||||
} else {
|
||||
//it's the inner error object only
|
||||
err = e;
|
||||
}
|
||||
let msg = "";
|
||||
if (err.code) {
|
||||
msg += err.code;
|
||||
msg += " - ";
|
||||
if (vm) {
|
||||
msg += vm.$sock.t("ErrorAPI" + err.code);
|
||||
}
|
||||
msg += "\n";
|
||||
}
|
||||
if (err.target) {
|
||||
msg += err.target;
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
if (err.message && !err.message.startsWith("ErrorAPI")) {
|
||||
//errapi already dealt with above no need to repeat it here
|
||||
msg += err.message;
|
||||
msg += "\n";
|
||||
}
|
||||
|
||||
if (err.details) {
|
||||
err.details.forEach(z => {
|
||||
let zerror = null;
|
||||
if (z.error) {
|
||||
zerror = z.error + " - ";
|
||||
}
|
||||
msg += `${zerror}${z.message}\n`;
|
||||
});
|
||||
}
|
||||
|
||||
//console.log("errorhandler:decodeError returning message:", msg);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
//Javascript Fetch API Response object?
|
||||
if (e instanceof Response) {
|
||||
return `http error: ${e.statusText} - ${e.status} Url: ${e.url}`;
|
||||
}
|
||||
|
||||
//last resort
|
||||
return JSON.stringify(e);
|
||||
}
|
||||
export default {
|
||||
handleGeneralError(message, source, lineno, colno, error) {
|
||||
let msg = "General error: \n" + message;
|
||||
if (source) {
|
||||
msg += "\nsource: " + source;
|
||||
}
|
||||
if (lineno) {
|
||||
msg += "\nlineno: " + lineno;
|
||||
}
|
||||
if (colno) {
|
||||
msg += "\ncolno: " + colno;
|
||||
}
|
||||
if (error) {
|
||||
if (typeof error === "object") {
|
||||
error = JSON.stringify(error);
|
||||
}
|
||||
msg += "\nerror: " + error;
|
||||
}
|
||||
dealWithError(msg);
|
||||
},
|
||||
handleVueError(err, vm, info) {
|
||||
let msg = "Vue error: \n" + decodeError(err, vm);
|
||||
if (err.fileName) {
|
||||
msg += "\nfilename: " + err.fileName;
|
||||
}
|
||||
if (err.lineNumber) {
|
||||
msg += "\nlineNumber: " + err.lineNumber;
|
||||
}
|
||||
if (info) {
|
||||
msg += "\ninfo: " + info;
|
||||
}
|
||||
if (err.stack) {
|
||||
msg += "\nSTACK:\n " + err.stack;
|
||||
}
|
||||
dealWithError(msg, vm);
|
||||
},
|
||||
handleVueWarning(wmsg, vm, trace) {
|
||||
let msg = "Vue warning: \n" + decodeError(wmsg, vm);
|
||||
if (trace) {
|
||||
msg += "\ntrace: " + trace;
|
||||
}
|
||||
dealWithError(msg, vm);
|
||||
},
|
||||
/////////////////////////////////////////////////
|
||||
// translate, log and return error
|
||||
//
|
||||
handleFormError(err, vm) {
|
||||
if (window.$gz.dev) {
|
||||
console.trace(err);
|
||||
}
|
||||
//called inside forms when things go unexpectedly wrong
|
||||
dealWithError(decodeError(err, vm), vm);
|
||||
},
|
||||
/////////////////////////////////////////////////
|
||||
// decode error into string suitable to display
|
||||
//
|
||||
errorToString(err, vm) {
|
||||
//called inside forms when things go unexpectedly wrong
|
||||
return decodeError(err, vm);
|
||||
}
|
||||
};
|
||||
/*
|
||||
ERROR CODES USED:
|
||||
Client error codes are all in the range of E16 to E999
|
||||
Server error codes are all in the range of E1000 to E1999
|
||||
API specific (logic) error codes are all in the range of 2000 to 3000
|
||||
|
||||
CLIENT ERROR CODES:
|
||||
E16 - ErrorUserNotAuthenticated
|
||||
E17 - ErrorServerUnresponsive
|
||||
E18 - Misc error without a translation key, unexpected throws etc or api error during server call, details in the message / Any error without a translation key defined basically
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user