diff --git a/backend/platform_settings_v2/exceptions.py b/backend/platform_settings_v2/exceptions.py
index 262571efb7..648fb8c7b9 100644
--- a/backend/platform_settings_v2/exceptions.py
+++ b/backend/platform_settings_v2/exceptions.py
@@ -25,7 +25,10 @@ class FoundActiveKey(APIException):
class ActiveKeyNotFound(APIException):
status_code = 404
- default_detail = "At least one active platform key should be available"
+ default_detail = (
+ "An active platform key is required to perform this action. "
+ "Configure one in [Platform Keys](/settings/platform) under Settings."
+ )
class InvalidRequest(APIException):
diff --git a/backend/workflow_manager/workflow_v2/exceptions.py b/backend/workflow_manager/workflow_v2/exceptions.py
index d6b10ede32..4bc050c13e 100644
--- a/backend/workflow_manager/workflow_v2/exceptions.py
+++ b/backend/workflow_manager/workflow_v2/exceptions.py
@@ -36,11 +36,6 @@ class InvalidRequest(APIException):
default_detail = "Invalid Request"
-class MissingEnvException(APIException):
- status_code = 500
- default_detail = "At least one active platform key should be available."
-
-
class InternalException(APIException):
"""Internal Error.
diff --git a/frontend/src/components/helpers/custom-markdown/CustomMarkdown.jsx b/frontend/src/components/helpers/custom-markdown/CustomMarkdown.jsx
index 88e48ea176..ff9bfe73ec 100644
--- a/frontend/src/components/helpers/custom-markdown/CustomMarkdown.jsx
+++ b/frontend/src/components/helpers/custom-markdown/CustomMarkdown.jsx
@@ -1,6 +1,7 @@
import { Typography } from "antd";
import PropTypes from "prop-types";
import { useMemo } from "react";
+import { Link as RouterLink } from "react-router-dom";
const { Text, Link, Paragraph } = Typography;
@@ -48,12 +49,17 @@ const CustomMarkdown = ({
{content}
);
- case "link":
+ case "link": {
+ const isInternal = url?.startsWith("/");
+ if (isInternal) {
+ return {content};
+ }
return (
{content}
);
+ }
case "newline":
return renderNewLines ?
: "\n";
default:
diff --git a/frontend/src/hooks/useExceptionHandler.jsx b/frontend/src/hooks/useExceptionHandler.jsx
index f8bf0ec685..54037820fc 100644
--- a/frontend/src/hooks/useExceptionHandler.jsx
+++ b/frontend/src/hooks/useExceptionHandler.jsx
@@ -1,8 +1,34 @@
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";
+import { useSessionStore } from "../store/session-store.js";
+
const useExceptionHandler = () => {
const navigate = useNavigate();
+ const { sessionDetails } = useSessionStore();
+
+ // Resolves relative markdown links [text](/path) to [text](/{orgName}/path)
+ const enrichMarkdownLinks = (message) => {
+ if (typeof message !== "string") {
+ return message;
+ }
+ const orgName = sessionDetails?.orgName;
+ if (!orgName) {
+ return message;
+ }
+ return message.replace(
+ /\[([^\]]+)\]\(\/((?!\/)[^)]+)\)/g,
+ (_, text, path) => `[${text}](/${orgName}/${path})`,
+ );
+ };
+
+ const buildAlert = (content, title, duration) => ({
+ type: "error",
+ content: enrichMarkdownLinks(content),
+ title,
+ duration,
+ });
+
const handleException = (
err,
errMessage = "Something went wrong",
@@ -11,27 +37,16 @@ const useExceptionHandler = () => {
duration = 0,
) => {
if (!err) {
- return {
- type: "error",
- content: errMessage,
- title: title,
- duration: duration,
- };
+ return buildAlert(errMessage, title, duration);
}
if (err.code === "ERR_NETWORK" && !navigator.onLine) {
- return {
- type: "error",
- content: "Please check your internet connection.",
- title: title,
- duration: duration,
- };
+ return buildAlert(
+ "Please check your internet connection.",
+ title,
+ duration,
+ );
} else if (err.code === "ERR_CANCELED") {
- return {
- type: "error",
- content: "Request has been canceled.",
- title: title,
- duration: duration,
- };
+ return buildAlert("Request has been canceled.", title, duration);
}
if (err?.response?.data) {
@@ -43,12 +58,7 @@ const useExceptionHandler = () => {
responseData.error || responseData.detail || responseData.message;
if (commonErrorMessage) {
- return {
- title: title,
- type: "error",
- content: commonErrorMessage,
- duration: duration,
- };
+ return buildAlert(commonErrorMessage, title, duration);
}
// Then handle specific error types
@@ -81,45 +91,24 @@ const useExceptionHandler = () => {
.join("\n");
}
}
- return {
- title: title,
- type: "error",
- content: errorMessage,
- duration: duration,
- };
+ return buildAlert(errorMessage, title, duration);
}
break;
case "subscription_error":
navigate("/subscription-expired");
- return {
- title: title,
- type: "error",
- content: errors,
- duration: duration,
- };
+ return buildAlert(errors, title, duration);
case "client_error":
case "server_error":
- return {
- title: title,
- type: "error",
- content: errors?.[0]?.detail ? errors[0].detail : errMessage,
- duration: duration,
- };
+ return buildAlert(
+ errors?.[0]?.detail ? errors[0].detail : errMessage,
+ title,
+ duration,
+ );
default:
- return {
- title: title,
- type: "error",
- content: errMessage,
- duration: duration,
- };
+ return buildAlert(errMessage, title, duration);
}
} else {
- return {
- title: title,
- type: "error",
- content: errMessage,
- duration: duration,
- };
+ return buildAlert(errMessage, title, duration);
}
};