Squashed commit of the following:
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 40s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 40s
commit 579f0878e5240dc17db69be1e0b0c0f5af7ef9fe
Author: Arno Kaimbacher <arno.kaimbacher@geosphere.at>
Date: Tue Jun 9 09:25:44 2026 +0200
feat: Refactor error handling in Dataset Edit form and improve validation messages
- Updated error handling in the Dataset Edit form to use a centralized formatError function for displaying validation messages.
- Enhanced user feedback by ensuring that error messages are displayed consistently across various fields.
- Modified the validation rule for arrayContainsTypes to provide clearer error messages for missing main and translated titles/abstracts.
- Introduced a new ValidationService to manage manual construction of validation errors.
- Updated Vite configuration to streamline asset loading and improve performance.
- Adjusted Inertia setup to utilize dynamic imports for page-specific assets.
- Cleaned up unnecessary comments and code in various files for better readability.
commit 5efddc2a58c0e164fef585cc7344c06155dbc2c1
Author: Arno Kaimbacher <arno.kaimbacher@geosphere.at>
Date: Mon Jan 12 17:02:47 2026 +0100
feat: add dataset change detection and form submission composables
- Implemented `useDatasetChangeDetection` for tracking unsaved changes in dataset forms, including comparisons for licenses, basic properties, files, coverage, and more.
- Added `useDatasetFormSubmission` for handling dataset form submissions with validation, success/error handling, and auto-save functionality.
This commit is contained in:
parent
0680879e2f
commit
9368a0dd8d
38 changed files with 5588 additions and 6181 deletions
|
|
@ -1,203 +1,50 @@
|
|||
// import { ValidationError } from '../errors/validation_error.js';
|
||||
import { errors } from '@vinejs/vine';
|
||||
import type { ErrorReporterContract, FieldContext } from '@vinejs/vine/types';
|
||||
import string from '@poppinss/utils/string';
|
||||
import { errors } from '@vinejs/vine'
|
||||
import type { ErrorReporterContract, FieldContext } from '@vinejs/vine/types'
|
||||
|
||||
/**
|
||||
* Shape of the Vanilla error node
|
||||
*/
|
||||
export type VanillaErrorNode = {
|
||||
[field: string]: string[];
|
||||
};
|
||||
export interface MessagesBagContract {
|
||||
get(pointer: string, rule: string, message: string, arrayExpressionPointer?: string, args?: any): string;
|
||||
}
|
||||
/**
|
||||
* Message bag exposes the API to pull the most appropriate message for a
|
||||
* given validation failure.
|
||||
*/
|
||||
export class MessagesBag implements MessagesBagContract {
|
||||
messages: Message;
|
||||
wildCardCallback;
|
||||
constructor(messages: string[]) {
|
||||
this.messages = messages;
|
||||
this.wildCardCallback = typeof this.messages['*'] === 'function' ? this.messages['*'] : undefined;
|
||||
}
|
||||
/**
|
||||
* Transform message by replace placeholders with runtime values
|
||||
*/
|
||||
transform(message: any, rule: string, pointer: string, args: any) {
|
||||
/**
|
||||
* No interpolation required
|
||||
*/
|
||||
if (!message.includes('{{')) {
|
||||
return message;
|
||||
}
|
||||
return string.interpolate(message, { rule, field: pointer, options: args || {} });
|
||||
}
|
||||
/**
|
||||
* Returns the most appropriate message for the validation failure.
|
||||
*/
|
||||
get(pointer: string, rule: string, message: string, arrayExpressionPointer: string, args: any) {
|
||||
let validationMessage = this.messages[`${pointer}.${rule}`];
|
||||
/**
|
||||
* Fetch message for the array expression pointer if it exists
|
||||
*/
|
||||
if (!validationMessage && arrayExpressionPointer) {
|
||||
validationMessage = this.messages[`${arrayExpressionPointer}.${rule}`];
|
||||
}
|
||||
/**
|
||||
* Fallback to the message for the rule
|
||||
*/
|
||||
if (!validationMessage) {
|
||||
validationMessage = this.messages[rule];
|
||||
}
|
||||
/**
|
||||
* Transform and return message. The wildcard callback is invoked when custom message
|
||||
* is not defined
|
||||
*/
|
||||
return validationMessage
|
||||
? this.transform(validationMessage, rule, pointer, args)
|
||||
: this.wildCardCallback
|
||||
? this.wildCardCallback(pointer, rule, arrayExpressionPointer, args)
|
||||
: message;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Shape of the error message collected by the SimpleErrorReporter
|
||||
*/
|
||||
type SimpleError = {
|
||||
message: string;
|
||||
field: string;
|
||||
rule: string;
|
||||
index?: number;
|
||||
meta?: Record<string, any>;
|
||||
};
|
||||
export interface Message {
|
||||
[key: string]: any;
|
||||
}
|
||||
/**
|
||||
* Simple error reporter collects error messages as an array of object.
|
||||
* Each object has following properties.
|
||||
*
|
||||
* - message: string
|
||||
* - field: string
|
||||
* - rule: string
|
||||
* - index?: number (in case of an array member)
|
||||
* - args?: Record<string, any>
|
||||
* Der VanillaErrorReporter sammelt Validierungsfehler im Standardformat,
|
||||
* damit die AdonisJS Session-Middleware sie korrekt verarbeiten (reducen) kann.
|
||||
*/
|
||||
export class VanillaErrorReporter implements ErrorReporterContract {
|
||||
// private messages;
|
||||
// private bail;
|
||||
/**
|
||||
* Boolean, um zu prüfen, ob Fehler vorliegen
|
||||
*/
|
||||
hasErrors: boolean = false
|
||||
|
||||
/**
|
||||
* Sammlung der Fehler als Array (erforderlich für AdonisJS 6 Session)
|
||||
*/
|
||||
errors: any[] = []
|
||||
|
||||
/**
|
||||
* Diese Methode wird von VineJS für jeden Validierungsfehler aufgerufen
|
||||
*/
|
||||
report(
|
||||
message: string,
|
||||
rule: string,
|
||||
field: FieldContext,
|
||||
meta?: Record<string, any>
|
||||
): void {
|
||||
this.hasErrors = true
|
||||
|
||||
/**
|
||||
* Boolean to know one or more errors have been reported
|
||||
*/
|
||||
hasErrors: boolean = false;
|
||||
/**
|
||||
* Collection of errors
|
||||
*/
|
||||
// errors: SimpleError[] = [];
|
||||
errors: Message = {};
|
||||
/**
|
||||
* Report an error.
|
||||
* Wir pushen das Objekt in das Array.
|
||||
* Das Feld 'field' erhält den vollständigen Pfad (z.B. "user.email").
|
||||
*/
|
||||
this.errors.push({
|
||||
message,
|
||||
rule,
|
||||
field: field.getFieldPath(),
|
||||
...meta,
|
||||
});
|
||||
}
|
||||
|
||||
// constructor(messages: MessagesBagContract) {
|
||||
// this.messages = messages;
|
||||
// }
|
||||
|
||||
report(message: string, rule: string, field: FieldContext, meta?: Record<string, any> | undefined): void {
|
||||
// const error: SimpleError = {
|
||||
// message,
|
||||
// rule,
|
||||
// field: field.getFieldPath()
|
||||
// };
|
||||
// if (meta) {
|
||||
// error.meta = meta;
|
||||
// }
|
||||
// if (field.isArrayMember) {
|
||||
// error.index = field.name as number;
|
||||
// }
|
||||
// this.errors.push(error);
|
||||
this.hasErrors = true;
|
||||
// if (this.errors[field.getFieldPath()]) {
|
||||
// this.errors[field.getFieldPath()]?.push(message);
|
||||
// } else {
|
||||
// this.errors[field.getFieldPath()] = [message];
|
||||
// }
|
||||
const error: SimpleError = {
|
||||
message,
|
||||
rule,
|
||||
field: field.getFieldPath(), // ?field.wildCardPath.split('.')[0] : field.getFieldPath(),
|
||||
};
|
||||
// field: 'titles.0.value'
|
||||
// message: 'Main Title is required'
|
||||
// rule: 'required' "required"
|
||||
|
||||
if (meta) {
|
||||
error.meta = meta;
|
||||
}
|
||||
// if (field.isArrayMember) {
|
||||
// error.index = field.name;
|
||||
// }
|
||||
this.hasErrors = true;
|
||||
|
||||
// var test = field.getFieldPath();
|
||||
|
||||
// this.errors.push(error);
|
||||
// if (this.errors[error.field]) {
|
||||
// this.errors[error.field]?.push(message);
|
||||
// }
|
||||
if (field.isArrayMember) {
|
||||
// Check if the field has wildCardPath and if the error field already exists
|
||||
if (this.errors[error.field]) {
|
||||
// Do nothing, as we don't want to push further messages
|
||||
} else {
|
||||
// If the error field already exists, push the message
|
||||
if (this.errors[error.field]) {
|
||||
this.errors[error.field].push(message);
|
||||
} else {
|
||||
this.errors[error.field] = [message];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.errors[error.field]) {
|
||||
this.errors[error.field]?.push(message);
|
||||
} else {
|
||||
this.errors[error.field] = [message];
|
||||
}
|
||||
}
|
||||
|
||||
// } else {
|
||||
// // normal field
|
||||
// this.errors[field.field] = [message];
|
||||
// }
|
||||
|
||||
/**
|
||||
* Collecting errors as per the JSONAPI spec
|
||||
*/
|
||||
// this.errors.push({
|
||||
// code: rule,
|
||||
// detail: message,
|
||||
// source: {
|
||||
// pointer: field.wildCardPath,
|
||||
// },
|
||||
// ...(meta ? { meta } : {}),
|
||||
// });
|
||||
|
||||
// let pointer: string = field.wildCardPath as string; //'display_name'
|
||||
// // if (field.isArrayMember) {
|
||||
// // this.errors[pointer] = field.name;
|
||||
// // }
|
||||
// this.errors[pointer] = this.errors[pointer] || [];
|
||||
// // this.errors[pointer].push(message);
|
||||
// this.errors[pointer].push(this.messages.get(pointer, rule, message, arrayExpressionPointer, args));
|
||||
}
|
||||
/**
|
||||
* Returns an instance of the validation error
|
||||
*/
|
||||
createError() {
|
||||
return new errors.E_VALIDATION_ERROR(this.errors);
|
||||
}
|
||||
}
|
||||
export {};
|
||||
/**
|
||||
* Erstellt die eigentliche Exception.
|
||||
* Da 'this.errors' nun ein Array ist, funktioniert .reduce()
|
||||
* in der Session-Middleware reibungslos.
|
||||
*/
|
||||
createError() {
|
||||
return new errors.E_VALIDATION_ERROR(this.errors);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue