fix(errors) : humanize backend error messages for end users
Add centralized error translation layer (humanizeError) that converts raw Symfony/Doctrine/API Platform messages into user-friendly French. Fix useApi to extract errors from all backend response formats (violations, error, message, hydra:description, detail). Add toast deduplication to prevent double display. Replace error toast icon (X → CircleX) to distinguish from the dismiss button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IconLucideX
|
||||
<IconLucideCircleX
|
||||
v-else-if="toast.type === 'error'"
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
@@ -64,6 +64,7 @@
|
||||
import { useToast } from '~/composables/useToast'
|
||||
import IconLucideCheck from '~icons/lucide/check'
|
||||
import IconLucideX from '~icons/lucide/x'
|
||||
import IconLucideCircleX from '~icons/lucide/circle-x'
|
||||
import IconLucideAlertTriangle from '~icons/lucide/alert-triangle'
|
||||
import IconLucideInfo from '~icons/lucide/info'
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@ import {
|
||||
type ModelTypeListResponse,
|
||||
} from "~/services/modelTypes";
|
||||
import { useToast } from "~/composables/useToast";
|
||||
import { humanizeError } from "~/shared/utils/errorMessages";
|
||||
import { invalidateEntityTypeCache } from "~/composables/useEntityTypes";
|
||||
|
||||
const DEFAULT_DESCRIPTION =
|
||||
@@ -183,7 +184,8 @@ useHead(() => ({
|
||||
title: headingText.value,
|
||||
}));
|
||||
|
||||
const extractErrorMessage = (error: unknown) => {
|
||||
const extractErrorMessage = (error: unknown): string => {
|
||||
let raw: string | null = null;
|
||||
if (error && typeof error === "object") {
|
||||
const maybeFetchError = error as {
|
||||
data?: Record<string, unknown>;
|
||||
@@ -192,21 +194,16 @@ const extractErrorMessage = (error: unknown) => {
|
||||
};
|
||||
if (maybeFetchError.data) {
|
||||
const data = maybeFetchError.data;
|
||||
if (typeof data.message === "string") {
|
||||
return data.message;
|
||||
}
|
||||
if (Array.isArray(data.message) && data.message.length > 0) {
|
||||
return data.message[0];
|
||||
}
|
||||
}
|
||||
if (typeof maybeFetchError.statusMessage === "string") {
|
||||
return maybeFetchError.statusMessage;
|
||||
}
|
||||
if (typeof maybeFetchError.message === "string") {
|
||||
return maybeFetchError.message;
|
||||
if (typeof data['hydra:description'] === "string") raw = data['hydra:description'];
|
||||
else if (typeof data.detail === "string") raw = data.detail;
|
||||
else if (typeof data.message === "string") raw = data.message;
|
||||
else if (Array.isArray(data.message) && data.message.length > 0) raw = data.message[0];
|
||||
else if (typeof data.error === "string") raw = data.error;
|
||||
}
|
||||
if (!raw && typeof maybeFetchError.statusMessage === "string") raw = maybeFetchError.statusMessage;
|
||||
if (!raw && typeof maybeFetchError.message === "string") raw = maybeFetchError.message;
|
||||
}
|
||||
return "Une erreur est survenue lors de la communication avec le serveur.";
|
||||
return humanizeError(raw);
|
||||
};
|
||||
|
||||
const refresh = async ({
|
||||
|
||||
Reference in New Issue
Block a user