fix: Etiketten-Import zeigt konkreten Grund statt generischem Fehler
Eine KI-erzeugte JSON ohne Kenntnis des echten Schemas (z.B. eigene Feldnamen wie xMm/yMm oder erfundene Elementtypen wie rectangle/svg) scheiterte bisher mit "Datei enthält keine gültige Etikettenvorlage" ohne Hinweis, was falsch ist. Jetzt wird pro Element benannt, was fehlt oder welcher Typ nicht unterstützt wird.
This commit is contained in:
1 parent
c6941a797f
commit
abe1f6e8cf
1 file changed
+36
-17
+36
-17
@@ -86,20 +86,35 @@ export interface LabelDesignerValue {
|
||||
// Loose runtime check for imported JSON (own export, or hand/AI-authored) -
|
||||
// only verifies the shape is plausible enough to load into the canvas;
|
||||
// the backend's own DTO validation is still the real boundary check on save.
|
||||
function isLabelElementArray(value: unknown): value is LabelElement[] {
|
||||
return (
|
||||
Array.isArray(value) &&
|
||||
value.every(
|
||||
(item) =>
|
||||
typeof item === "object" &&
|
||||
item !== null &&
|
||||
"id" in item &&
|
||||
"type" in item &&
|
||||
"x" in item &&
|
||||
"y" in item &&
|
||||
ELEMENT_TYPES.includes((item as { type: unknown }).type as (typeof ELEMENT_TYPES)[number]),
|
||||
)
|
||||
);
|
||||
// Returns a specific reason per bad element instead of a flat true/false, so
|
||||
// an AI-authored file that guessed the wrong schema tells the user exactly
|
||||
// what to fix rather than a generic "invalid file".
|
||||
function validateImportedElements(value: unknown): { elements: LabelElement[] } | { errors: string[] } {
|
||||
if (!Array.isArray(value)) {
|
||||
return { errors: ['Die Datei enthält kein "elements"-Array.'] };
|
||||
}
|
||||
const errors: string[] = [];
|
||||
value.forEach((item, index) => {
|
||||
const label = typeof item === "object" && item && "id" in item ? String((item as { id: unknown }).id) : `#${index + 1}`;
|
||||
if (typeof item !== "object" || item === null) {
|
||||
errors.push(`Element ${label}: kein Objekt.`);
|
||||
return;
|
||||
}
|
||||
if (!("x" in item) || !("y" in item)) {
|
||||
errors.push(`Element ${label}: "x"/"y" fehlen (nicht "xMm"/"yMm").`);
|
||||
return;
|
||||
}
|
||||
const type = (item as { type?: unknown }).type;
|
||||
if (!ELEMENT_TYPES.includes(type as (typeof ELEMENT_TYPES)[number])) {
|
||||
errors.push(
|
||||
`Element ${label}: Typ "${String(type)}" wird nicht unterstützt (nur ${ELEMENT_TYPES.join(", ")}).`,
|
||||
);
|
||||
}
|
||||
});
|
||||
if (errors.length > 0) {
|
||||
return { errors };
|
||||
}
|
||||
return { elements: value as LabelElement[] };
|
||||
}
|
||||
|
||||
function slugify(name: string): string {
|
||||
@@ -235,11 +250,15 @@ export function LabelDesigner({ initial, onSubmit, submitLabel }: LabelDesignerP
|
||||
const importedElements = Array.isArray(parsed)
|
||||
? parsed
|
||||
: (parsed as { elements?: unknown })?.elements;
|
||||
if (!isLabelElementArray(importedElements)) {
|
||||
toast.error("Datei enthält keine gültige Etikettenvorlage.");
|
||||
const result = validateImportedElements(importedElements);
|
||||
if ("errors" in result) {
|
||||
toast.error("Vorlage konnte nicht importiert werden", {
|
||||
description: result.errors.slice(0, 5).join(" · "),
|
||||
duration: 15000,
|
||||
});
|
||||
return;
|
||||
}
|
||||
setElements(importedElements.map((element) => ({ ...element, id: newId() })));
|
||||
setElements(result.elements.map((element) => ({ ...element, id: newId() })));
|
||||
if (!Array.isArray(parsed)) {
|
||||
const value = parsed as Partial<LabelDesignerValue>;
|
||||
if (typeof value.name === "string" && value.name && !name) setName(value.name);
|
||||
|
||||
Reference in new issue
Block a user