diff --git a/src/components/Configure/content/ConfigureInstallationBase.tsx b/src/components/Configure/content/ConfigureInstallationBase.tsx index db656a23..d36ae049 100644 --- a/src/components/Configure/content/ConfigureInstallationBase.tsx +++ b/src/components/Configure/content/ConfigureInstallationBase.tsx @@ -192,7 +192,7 @@ export function ConfigureInstallationBase({ }} > {errorMsg && ( - + {typeof errorMsg === "string" ? errorMsg : "Installation Failed."} )} diff --git a/src/components/Configure/content/fields/ReadFields.tsx b/src/components/Configure/content/fields/ReadFields.tsx index b4558b8b..d991b607 100644 --- a/src/components/Configure/content/fields/ReadFields.tsx +++ b/src/components/Configure/content/fields/ReadFields.tsx @@ -11,7 +11,13 @@ export function ReadFields() { useClearOldFieldMappings(); return ( - <> +
@@ -20,6 +26,6 @@ export function ReadFields() { - +
); } diff --git a/src/components/FormErrorBox.tsx b/src/components/FormErrorBox.tsx index d6692fca..ccbc9cfc 100644 --- a/src/components/FormErrorBox.tsx +++ b/src/components/FormErrorBox.tsx @@ -7,11 +7,73 @@ const defaultStyle = { padding: ".5rem 1rem", }; +/** Separates detail and remedy in serialized error strings from handleServerError. */ +const REMEDY_DELIMITER = "\x1e"; + +function parseErrorMessage(message: string): { detail: string; remedy?: string } { + const delimiterIndex = message.indexOf(REMEDY_DELIMITER); + if (delimiterIndex === -1) { + return { detail: message }; + } + + return { + detail: message.slice(0, delimiterIndex), + remedy: message.slice(delimiterIndex + REMEDY_DELIMITER.length), + }; +} + +function ErrorMessageContent({ message }: { message: string }) { + const { detail, remedy } = parseErrorMessage(message); + + return ( + <> +

+ {detail} +

+ {remedy && ( +
+ + How to fix + +

+ {remedy} +

+
+ )} + + ); +} + type FormErrorBoxProps = { children: React.ReactNode; style?: React.CSSProperties; }; export function FormErrorBox({ children, style }: FormErrorBoxProps) { - return {children}; + return ( + + {typeof children === "string" ? ( + + ) : ( + children + )} + + ); } diff --git a/src/utils/handleServerError.ts b/src/utils/handleServerError.ts index 236ecc7c..f378f80d 100644 --- a/src/utils/handleServerError.ts +++ b/src/utils/handleServerError.ts @@ -1,5 +1,8 @@ import { ResponseError } from "@generated/api/src"; +/** Separates detail and remedy in error strings passed to setError. */ +const REMEDY_DELIMITER = "\x1e"; + /** * handles server error generated by sdk (Response Error) and calls setError callback if provided * @param error could be unknown error or ResponseError @@ -37,7 +40,9 @@ export const handleServerError = async ( } } - const combinedErrorMessage = `${errorMsg} ${errorBody?.remedy ? `\n\n[Remedy] ${errorBody.remedy}` : ""}`; + const combinedErrorMessage = errorBody?.remedy + ? `${errorMsg?.trimEnd() ?? ""}${REMEDY_DELIMITER}${errorBody.remedy}` + : (errorMsg ?? ""); if (setError) setError(combinedErrorMessage); } catch (e) { console.error("Error parsing error response body:", e); // the response body could already be parsed