admin: associate inline field errors with their inputs

network assignment rows, activity filters, and the settings password pair now mark the offending input with aria-invalid and point it at the error text with aria-describedby. the prefix validator returns the row and field it is about, and any row mutation clears a message that named a position. settings numeric fields carry aria-invalid on an unparseable value.
This commit is contained in:
2026-08-29 12:08:19 +02:00
parent 317d5dd4f8
commit 59d6be98f8
8 changed files with 295 additions and 27 deletions
+13 -4
View File
@@ -55,11 +55,20 @@ export function isDirty(state: PrefixEditorState): boolean {
});
}
export function firstProblem(rows: PrefixRow[]): string | null {
for (const [i, row] of rows.entries()) {
if (row.prefix.trim() === "") return `Row ${i + 1}: prefix is required.`;
/** Which input the message is about, so the editor can point that input at it. */
export interface PrefixProblem {
index: number;
field: "prefix" | "priority";
message: string;
}
export function firstProblem(rows: PrefixRow[]): PrefixProblem | null {
for (const [index, row] of rows.entries()) {
if (row.prefix.trim() === "")
return { index, field: "prefix", message: `Row ${index + 1}: prefix is required.` };
const priority = row.priority.trim();
if (priority !== "" && !/^\d+$/.test(priority)) return `Row ${i + 1}: priority must be a whole number.`;
if (priority !== "" && !/^\d+$/.test(priority))
return { index, field: "priority", message: `Row ${index + 1}: priority must be a whole number.` };
}
return null;
}