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); } };