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.
129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
import { join, isAbsolute } from 'node:path';
|
|
import type { BodyParserConfig } from '#models/types';
|
|
import { createId } from '@paralleldrive/cuid2';
|
|
import { tmpdir } from 'node:os';
|
|
import config from '@adonisjs/core/services/config';
|
|
import Dataset from '#models/dataset';
|
|
import { TransactionClientContract } from '@adonisjs/lucid/types/database';
|
|
import Person from '#models/person';
|
|
|
|
interface Dictionary {
|
|
[index: string]: string;
|
|
}
|
|
|
|
export function sum(a: number, b: number): number {
|
|
return a + b;
|
|
}
|
|
|
|
export function getDomain(host: string): string {
|
|
// $myhost = strtolower(trim($host));
|
|
let myHost: string = host.trim().toLocaleLowerCase();
|
|
// $count = substr_count($myhost, '.');
|
|
const count: number = myHost.split(',').length - 1;
|
|
|
|
if (count == 2) {
|
|
const words = myHost.split('.');
|
|
if (words[1].length > 3) {
|
|
myHost = myHost.split('.', 2)[1];
|
|
}
|
|
} else if (count > 2) {
|
|
myHost = getDomain(myHost.split('.', 2)[1]);
|
|
}
|
|
myHost = myHost.replace(new RegExp(/^.*:\/\//i, 'g'), '');
|
|
return myHost;
|
|
}
|
|
|
|
export function preg_match(regex: RegExp, str: string) {
|
|
const result: boolean = regex.test(str);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Returns the tmp path for storing the files temporarly
|
|
*/
|
|
export function getTmpPath(config: BodyParserConfig['multipart']): string {
|
|
if (typeof config.tmpFileName === 'function') {
|
|
const tmpPath = config.tmpFileName();
|
|
return isAbsolute(tmpPath) ? tmpPath : join(tmpdir(), tmpPath);
|
|
}
|
|
|
|
return join(tmpdir(), createId());
|
|
}
|
|
/**
|
|
* Returns config for a given type
|
|
*/
|
|
export function getConfigFor<K extends keyof BodyParserConfig>(type: K): BodyParserConfig[K] {
|
|
const bodyParserConfig: BodyParserConfig = config.get('bodyparser');
|
|
const configType = bodyParserConfig[type];
|
|
return configType;
|
|
}
|
|
|
|
export function parseBytesSize(size: string): number {
|
|
const units: Record<string, number> = {
|
|
kb: 1024,
|
|
mb: 1024 * 1024,
|
|
gb: 1024 * 1024 * 1024,
|
|
tb: 1024 * 1024 * 1024 * 1024,
|
|
};
|
|
|
|
const match = size.match(/^(\d+)(kb|mb|gb|tb)$/i); // Regex to match size format
|
|
|
|
if (!match) {
|
|
throw new Error('Invalid size format');
|
|
}
|
|
|
|
const [, value, unit] = match;
|
|
return parseInt(value) * units[unit.toLowerCase()];
|
|
}
|
|
|
|
// Helper function to format bytes as human-readable text
|
|
|
|
export function formatBytes(bytes: number): string {
|
|
if (bytes === 0) return '0 Bytes';
|
|
const k = 1024;
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
|
|
export async function savePersons(dataset: Dataset, persons: any[], role: string, trx: TransactionClientContract) {
|
|
for (const [key, person] of persons.entries()) {
|
|
const pivotData = {
|
|
role: role,
|
|
sort_order: key + 1,
|
|
allow_email_contact: false,
|
|
...extractPivotAttributes(person), // Merge pivot attributes here
|
|
};
|
|
|
|
if (person.id !== undefined) {
|
|
await dataset
|
|
.useTransaction(trx)
|
|
.related('persons')
|
|
.attach({
|
|
[person.id]: pivotData,
|
|
});
|
|
} else {
|
|
const dataPerson = new Person();
|
|
dataPerson.fill(person);
|
|
await dataset.useTransaction(trx).related('persons').save(dataPerson, false, pivotData);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function to extract pivot attributes from a person object
|
|
function extractPivotAttributes(person: any) {
|
|
const pivotAttributes: Dictionary = {};
|
|
for (const key in person) {
|
|
if (key.startsWith('pivot_')) {
|
|
// pivotAttributes[key] = person[key];
|
|
const cleanKey = key.replace('pivot_', ''); // Remove 'pivot_' prefix
|
|
pivotAttributes[cleanKey] = person[key];
|
|
}
|
|
}
|
|
return pivotAttributes;
|
|
}
|
|
|
|
// in #app/utils/utility-functions
|
|
export function errorMessage(error: unknown): string {
|
|
return error instanceof Error ? error.message : String(error);
|
|
}
|