mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
fix(imex): show validation error details on import failure
Include failed field paths in DataValidationFailedError message and display them in the snackbar, making it easier to debug import issues.
This commit is contained in:
parent
10d652a382
commit
d2a13d21e3
3 changed files with 58 additions and 5 deletions
|
|
@ -28,6 +28,7 @@ import {
|
|||
DialogConfirmUrlImportData,
|
||||
} from '../dialog-confirm-url-import/dialog-confirm-url-import.component';
|
||||
import { Log } from '../../core/log';
|
||||
import { DataValidationFailedError } from '../../pfapi/api/errors/errors';
|
||||
|
||||
@Component({
|
||||
selector: 'file-imex',
|
||||
|
|
@ -186,10 +187,19 @@ export class FileImexComponent implements OnInit {
|
|||
// this._snackService.open({ type: 'SUCCESS', msg: 'Data imported successfully!' });
|
||||
} catch (e) {
|
||||
Log.err('Import process failed', e);
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: T.FILE_IMEX.S_ERR_IMPORT_FAILED,
|
||||
});
|
||||
|
||||
if (e instanceof DataValidationFailedError) {
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: `Import failed: ${e.message}`,
|
||||
isSkipTranslate: true,
|
||||
});
|
||||
} else {
|
||||
this._snackService.open({
|
||||
type: 'ERROR',
|
||||
msg: T.FILE_IMEX.S_ERR_IMPORT_FAILED,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ describe('DataValidationFailedError', () => {
|
|||
const error = new DataValidationFailedError(validationResult as any);
|
||||
|
||||
expect(error.name).toBe('DataValidationFailedError');
|
||||
expect(error.message).toContain('test.path');
|
||||
expect(error.message).toContain('another.path');
|
||||
expect(error.additionalLog).toBeDefined();
|
||||
expect(error.additionalLog).toContain('test.path');
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
|
|
@ -66,6 +68,26 @@ describe('DataValidationFailedError', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should include error paths in message with count for many errors', () => {
|
||||
const validationResult = {
|
||||
errors: [
|
||||
{ path: 'path.one', expected: 'string', value: 1 },
|
||||
{ path: 'path.two', expected: 'string', value: 2 },
|
||||
{ path: 'path.three', expected: 'string', value: 3 },
|
||||
{ path: 'path.four', expected: 'string', value: 4 },
|
||||
{ path: 'path.five', expected: 'string', value: 5 },
|
||||
],
|
||||
};
|
||||
|
||||
const error = new DataValidationFailedError(validationResult as any);
|
||||
|
||||
expect(error.message).toContain('path.one');
|
||||
expect(error.message).toContain('path.two');
|
||||
expect(error.message).toContain('path.three');
|
||||
expect(error.message).toContain('(+2 more)');
|
||||
expect(error.message).not.toContain('path.four');
|
||||
});
|
||||
|
||||
it('should truncate long error strings to 400 characters', () => {
|
||||
const longError = { message: 'x'.repeat(500) };
|
||||
const validationResult = {
|
||||
|
|
@ -87,6 +109,7 @@ describe('DataValidationFailedError', () => {
|
|||
const error = new DataValidationFailedError(validationResult as any);
|
||||
|
||||
expect(error.name).toBe('DataValidationFailedError');
|
||||
expect(error.message).toBe('Data validation failed');
|
||||
expect(consoleLogSpy).toHaveBeenCalledWith(
|
||||
'[pf]',
|
||||
'validation result: ',
|
||||
|
|
|
|||
|
|
@ -427,7 +427,8 @@ export class DataValidationFailedError extends Error {
|
|||
additionalLog?: string;
|
||||
|
||||
constructor(validationResult: IValidation<AllModelData<any>>) {
|
||||
super('DataValidationFailedError');
|
||||
const errorSummary = DataValidationFailedError._buildErrorSummary(validationResult);
|
||||
super(errorSummary);
|
||||
PFLog.log('validation result: ', validationResult);
|
||||
|
||||
try {
|
||||
|
|
@ -441,6 +442,25 @@ export class DataValidationFailedError extends Error {
|
|||
PFLog.err('Failed to stringify validation errors:', e);
|
||||
}
|
||||
}
|
||||
|
||||
private static _buildErrorSummary(
|
||||
validationResult: IValidation<AllModelData<any>>,
|
||||
): string {
|
||||
try {
|
||||
if ('errors' in validationResult && Array.isArray(validationResult.errors)) {
|
||||
const errors = validationResult.errors as IValidation.IError[];
|
||||
const paths = errors
|
||||
.slice(0, 3)
|
||||
.map((e) => e.path)
|
||||
.join(', ');
|
||||
const suffix = errors.length > 3 ? ` (+${errors.length - 3} more)` : '';
|
||||
return `Validation failed at: ${paths}${suffix}`;
|
||||
}
|
||||
} catch {
|
||||
// Fall through to default message
|
||||
}
|
||||
return 'Data validation failed';
|
||||
}
|
||||
}
|
||||
|
||||
export class ModelVersionToImportNewerThanLocalError extends AdditionalLogErrorBase {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue