Skip to content

Commit 49932e2

Browse files
authored
Merge pull request #1762 from kleros/chore/parse-wagmi-simulate-error
chore(web): better-error-display-and-evidence-search
2 parents 8c41958 + 5f5771d commit 49932e2

File tree

9 files changed

+90
-12
lines changed

9 files changed

+90
-12
lines changed
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { type SimulateContractErrorType } from "@wagmi/core";
2+
3+
type ExtendedWagmiError = SimulateContractErrorType & { shortMessage?: string; metaMessages?: string[] };
4+
5+
/**
6+
* @param error
7+
* @description Tries to extract the human readable error message, otherwise reverts to error.message
8+
* @returns Human readable error if possible
9+
*/
10+
export const parseWagmiError = (error: SimulateContractErrorType) => {
11+
const extError = error as ExtendedWagmiError;
12+
13+
const metaMessage = extError?.metaMessages?.[0];
14+
const shortMessage = extError?.shortMessage;
15+
16+
return metaMessage ?? shortMessage ?? error.message;
17+
};

web-devtools/src/utils/wrapWithToast.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { toast, ToastPosition, Theme } from "react-toastify";
22
import { type PublicClient, type TransactionReceipt } from "viem";
33

4+
import { parseWagmiError } from "./parseWagmiError";
5+
46
export const OPTIONS = {
57
position: "top-center" as ToastPosition,
68
autoClose: 5000,
@@ -35,11 +37,11 @@ export async function wrapWithToast(
3537
})
3638
)
3739
.catch((error) => {
38-
toast.error(error.shortMessage ?? error.message, OPTIONS);
40+
toast.error(parseWagmiError(error), OPTIONS);
3941
return { status: false };
4042
});
4143
}
4244

4345
export async function catchShortMessage(promise: Promise<any>) {
44-
return await promise.catch((error) => toast.error(error.shortMessage ?? error.message, OPTIONS));
46+
return await promise.catch((error) => toast.error(parseWagmiError(error), OPTIONS));
4547
}

web/src/components/FileViewer/index.tsx

+21-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const StyledDocViewer = styled(DocViewer)`
2828
* @returns renders the file
2929
*/
3030
const FileViewer: React.FC<{ url: string }> = ({ url }) => {
31-
const docs = [{ uri: url }];
31+
const docs = [{ uri: url, fileName: fileNameIfIpfsUrl(url) }];
3232
return (
3333
<Wrapper className="file-viewer-wrapper">
3434
<StyledDocViewer
@@ -50,4 +50,24 @@ const FileViewer: React.FC<{ url: string }> = ({ url }) => {
5050
);
5151
};
5252

53+
const fileNameIfIpfsUrl = (url: string) => {
54+
if (!url || typeof url !== "string") {
55+
return "document";
56+
}
57+
const ipfsPattern = /(?:ipfs:\/\/|https?:\/\/(?:[A-Za-z0-9.-]+)\/ipfs\/)([A-Za-z0-9]+[A-Za-z0-9\-_]*)\/?(.*)/;
58+
59+
const match = ipfsPattern.exec(url);
60+
61+
if (match) {
62+
const ipfsHash = match[1];
63+
const path = match[2] || "";
64+
65+
const sanitizedPath = path.replace(/\//g, "_");
66+
67+
return `ipfs-${ipfsHash}${sanitizedPath ? "_" + sanitizedPath : ""}`;
68+
} else {
69+
return "document";
70+
}
71+
};
72+
5373
export default FileViewer;

web/src/hooks/queries/useEvidences.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useQuery } from "@tanstack/react-query";
22

33
import { REFETCH_INTERVAL } from "consts/index";
44
import { useGraphqlBatcher } from "context/GraphqlBatcher";
5+
import { transformSearch } from "utils/transformSearch";
56

67
import { graphql } from "src/graphql";
78
import { EvidenceDetailsFragment, EvidencesQuery } from "src/graphql/graphql";
@@ -45,6 +46,8 @@ export const useEvidences = (evidenceGroup?: string, keywords?: string) => {
4546
const { graphqlBatcher } = useGraphqlBatcher();
4647

4748
const document = keywords ? evidenceSearchQuery : evidencesQuery;
49+
const transformedKeywords = transformSearch(keywords);
50+
4851
return useQuery<{ evidences: EvidenceDetailsFragment[] }>({
4952
queryKey: [keywords ? `evidenceSearchQuery${evidenceGroup}-${keywords}` : `evidencesQuery${evidenceGroup}`],
5053
enabled: isEnabled,
@@ -53,7 +56,7 @@ export const useEvidences = (evidenceGroup?: string, keywords?: string) => {
5356
const result = await graphqlBatcher.fetch({
5457
id: crypto.randomUUID(),
5558
document: document,
56-
variables: { evidenceGroupID: evidenceGroup?.toString(), keywords: keywords },
59+
variables: { evidenceGroupID: evidenceGroup?.toString(), keywords: transformedKeywords },
5760
});
5861

5962
return keywords ? { evidences: [...result.evidenceSearch] } : result;

web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useCallback, useEffect, useMemo } from "react";
2+
import styled from "styled-components";
23

34
import { useParams } from "react-router-dom";
45
import { useAccount, usePublicClient } from "wagmi";
@@ -19,10 +20,10 @@ import {
1920
} from "hooks/contracts/generated";
2021
import { useCourtDetails } from "hooks/queries/useCourtDetails";
2122
import { isUndefined } from "utils/index";
23+
import { parseWagmiError } from "utils/parseWagmiError";
2224
import { wrapWithToast } from "utils/wrapWithToast";
2325

2426
import { EnsureChain } from "components/EnsureChain";
25-
import styled from "styled-components";
2627

2728
export enum ActionType {
2829
allowance = "allowance",
@@ -154,9 +155,9 @@ const StakeWithdrawButton: React.FC<IActionButton> = ({
154155

155156
useEffect(() => {
156157
if (setStakeError) {
157-
setErrorMsg(setStakeError?.shortMessage ?? setStakeError.message);
158+
setErrorMsg(parseWagmiError(setStakeError));
158159
}
159-
}, [setStakeError]);
160+
}, [setStakeError, setErrorMsg]);
160161

161162
const { text, checkDisabled, onClick } = buttonProps[isAllowance ? ActionType.allowance : action];
162163
return (

web/src/pages/Resolver/NavigationButtons/SubmitDisputeButton.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import {
1414
useSimulateDisputeResolverCreateDisputeForTemplate,
1515
} from "hooks/contracts/generated";
1616
import { isUndefined } from "utils/index";
17+
import { parseWagmiError } from "utils/parseWagmiError";
1718
import { prepareArbitratorExtradata } from "utils/prepareArbitratorExtradata";
1819
import { wrapWithToast } from "utils/wrapWithToast";
1920

2021
import { EnsureChain } from "components/EnsureChain";
21-
import Popup, { PopupType } from "components/Popup";
22-
2322
import { ErrorButtonMessage } from "components/ErrorButtonMessage";
23+
import Popup, { PopupType } from "components/Popup";
2424
import ClosedCircleIcon from "components/StyledIcons/ClosedCircleIcon";
2525

2626
const StyledButton = styled(Button)``;
@@ -66,7 +66,7 @@ const SubmitDisputeButton: React.FC = () => {
6666
const errorMsg = useMemo(() => {
6767
if (insufficientBalance) return "Insufficient balance";
6868
else if (error) {
69-
return error?.shortMessage ?? error.message;
69+
return parseWagmiError(error);
7070
}
7171
return null;
7272
}, [error, insufficientBalance]);

web/src/utils/parseWagmiError.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { type SimulateContractErrorType } from "@wagmi/core";
2+
3+
type ExtendedWagmiError = SimulateContractErrorType & { shortMessage?: string; metaMessages?: string[] };
4+
5+
/**
6+
* @param error
7+
* @description Tries to extract the human readable error message, otherwise reverts to error.message
8+
* @returns Human readable error if possible
9+
*/
10+
export const parseWagmiError = (error: SimulateContractErrorType) => {
11+
const extError = error as ExtendedWagmiError;
12+
13+
const metaMessage = extError?.metaMessages?.[0];
14+
const shortMessage = extError?.shortMessage;
15+
16+
return metaMessage ?? shortMessage ?? error.message;
17+
};

web/src/utils/transformSearch.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/**
2+
*
3+
* @param searchString
4+
* @returns A search string to better search with fullTextSearch
5+
*/
6+
export const transformSearch = (searchString?: string) => {
7+
if (!searchString) return null;
8+
const words = searchString
9+
.split(/\s+/)
10+
.map((word) => word.trim())
11+
.filter(Boolean);
12+
13+
const transformedWords = words.map((word) => `${word} | ${word}:*`);
14+
15+
return transformedWords.join(" | ");
16+
};

web/src/utils/wrapWithToast.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { toast, ToastPosition, Theme } from "react-toastify";
22
import { PublicClient, TransactionReceipt } from "viem";
33

4+
import { parseWagmiError } from "./parseWagmiError";
5+
46
export const OPTIONS = {
57
position: "top-center" as ToastPosition,
68
autoClose: 5000,
@@ -39,11 +41,11 @@ export async function wrapWithToast(
3941
})
4042
)
4143
.catch((error) => {
42-
toast.error(error.shortMessage ?? error.message, OPTIONS);
44+
toast.error(parseWagmiError(error), OPTIONS);
4345
return { status: false };
4446
});
4547
}
4648

4749
export async function catchShortMessage(promise: Promise<any>) {
48-
return await promise.catch((error) => toast.error(error.shortMessage ?? error.message, OPTIONS));
50+
return await promise.catch((error) => toast.error(parseWagmiError(error), OPTIONS));
4951
}

0 commit comments

Comments
 (0)