diff --git a/src/FetchRequestDetail.tsx b/src/FetchRequestDetail.tsx index 560013b..b55ad77 100644 --- a/src/FetchRequestDetail.tsx +++ b/src/FetchRequestDetail.tsx @@ -36,7 +36,7 @@ import type { SSEEvent, ProgressMessage, } from "./features/fetch-requests"; -import { RETRY_MAX } from "./features/fetch-requests"; +import { RETRY_MAX, formatApiError } from "./features/fetch-requests"; import { useConfig } from "../react-openapi"; const statusColors: Record = { @@ -318,8 +318,8 @@ export default function FetchRequestDetail() { if (!id) return; try { await updateMutation.mutateAsync({ id, data: { status: "pending" } }); - } catch { - // handled by react query + } catch (err: any) { + setFailNotif(formatApiError(err)); } }; diff --git a/src/FetchRequests.tsx b/src/FetchRequests.tsx index d63d204..d1f5c8c 100644 --- a/src/FetchRequests.tsx +++ b/src/FetchRequests.tsx @@ -55,7 +55,7 @@ import type { FileSource, EmailSource, } from "./features/fetch-requests"; -import { RETRY_MAX } from "./features/fetch-requests"; +import { RETRY_MAX, formatApiError } from "./features/fetch-requests"; import { useNavigate } from "react-router-dom"; import { useResourceByName, useConfig } from "../react-openapi"; @@ -180,7 +180,7 @@ export default function FetchRequests() { if (err?.response?.status === 409) { setSnackbar({ message: "Duplicate — same fingerprint already exists", severity: "error" }); } else { - setSnackbar({ message: err?.response?.data?.detail || "Failed to create fetch request", severity: "error" }); + setSnackbar({ message: formatApiError(err) || "Failed to create fetch request", severity: "error" }); } } }; diff --git a/src/features/fetch-requests/fetch-requests.models.ts b/src/features/fetch-requests/fetch-requests.models.ts index 1265b4a..ebe0399 100644 --- a/src/features/fetch-requests/fetch-requests.models.ts +++ b/src/features/fetch-requests/fetch-requests.models.ts @@ -113,4 +113,21 @@ export interface FetchRequestFilters { source_type?: "file" | "email"; } +export function formatApiError(err: any): string { + if (!err?.response) return err?.message || "Request failed"; + const data = err.response.data; + const status = err.response.status; + + if (status === 422 && Array.isArray(data?.detail)) { + return data.detail.map((d: any) => { + const field = d.loc?.filter((s: string) => s !== "body").pop() || "field"; + if (d.type === "value_error.missing") return `Missing: ${field}`; + return `${field}: ${d.msg}`; + }).join("; "); + } + + if (typeof data?.detail === "string") return data.detail; + return `Request failed (${status})`; +} + export const RETRY_MAX = 3; diff --git a/src/features/fetch-requests/index.ts b/src/features/fetch-requests/index.ts index 094ee8c..cd21072 100644 --- a/src/features/fetch-requests/index.ts +++ b/src/features/fetch-requests/index.ts @@ -15,7 +15,7 @@ export type { SSEEventStatus, ProgressMessage, } from "./fetch-requests.models"; -export { RETRY_MAX } from "./fetch-requests.models"; +export { RETRY_MAX, formatApiError } from "./fetch-requests.models"; export { useFetchRequestsList, useFetchRequest,