fix(frontend): enforce lint locally and in CI, fix all pre-existing violations
## Pre-commit hook
- Add .husky/pre-commit at repo root: runs `cd frontend && npm run lint`
- Update prepare script in package.json to auto-configure git hooks path
on npm install (git -C .. config core.hooksPath .husky)
- Add lint step to CI unit-tests job so it catches issues before tests run
- Add generated dirs to .prettierignore (paraglide_bak*, test-results, .auth)
- Add src/lib/paraglide_bak* to .gitignore so ESLint can ignore them
## ESLint fixes (all pre-existing)
- Disable svelte/no-navigation-without-resolve: false positive in SvelteKit
(rule targets Svelte 5 standalone routing, not SvelteKit <a href>)
- Fix svelte/require-each-key: add (item.id)/(item) keys to all {#each} blocks
across 10 files — improves Svelte reconciliation performance
- Fix svelte/prefer-writable-derived in PersonTypeahead: $state+$effect → $derived
- Fix svelte/prefer-svelte-reactivity: URLSearchParams → SvelteURLSearchParams,
Map → SvelteMap (enables Svelte reactive tracking)
- Fix @typescript-eslint/no-unused-vars: remove dead imports/variables
## Prettier
- Run npm run format to bring all source files in line with .prettierrc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,20 +5,20 @@ import * as m from '$lib/paraglide/messages.js';
|
||||
* Keep in sync with backend/src/main/java/org/raddatz/familienarchiv/exception/ErrorCode.java
|
||||
*/
|
||||
export type ErrorCode =
|
||||
| 'DOCUMENT_NOT_FOUND'
|
||||
| 'DOCUMENT_NO_FILE'
|
||||
| 'FILE_NOT_FOUND'
|
||||
| 'FILE_UPLOAD_FAILED'
|
||||
| 'USER_NOT_FOUND'
|
||||
| 'IMPORT_ALREADY_RUNNING'
|
||||
| 'UNAUTHORIZED'
|
||||
| 'FORBIDDEN'
|
||||
| 'VALIDATION_ERROR'
|
||||
| 'INTERNAL_ERROR';
|
||||
| 'DOCUMENT_NOT_FOUND'
|
||||
| 'DOCUMENT_NO_FILE'
|
||||
| 'FILE_NOT_FOUND'
|
||||
| 'FILE_UPLOAD_FAILED'
|
||||
| 'USER_NOT_FOUND'
|
||||
| 'IMPORT_ALREADY_RUNNING'
|
||||
| 'UNAUTHORIZED'
|
||||
| 'FORBIDDEN'
|
||||
| 'VALIDATION_ERROR'
|
||||
| 'INTERNAL_ERROR';
|
||||
|
||||
export interface BackendError {
|
||||
code: ErrorCode;
|
||||
message: string; // English developer message — not shown to users
|
||||
code: ErrorCode;
|
||||
message: string; // English developer message — not shown to users
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,29 +26,39 @@ export interface BackendError {
|
||||
* Returns null if the body is not valid JSON or does not contain a code field.
|
||||
*/
|
||||
export async function parseBackendError(res: Response): Promise<BackendError | null> {
|
||||
try {
|
||||
const body = await res.json();
|
||||
if (body && typeof body.code === 'string') {
|
||||
return body as BackendError;
|
||||
}
|
||||
} catch {
|
||||
// Body was not JSON
|
||||
}
|
||||
return null;
|
||||
try {
|
||||
const body = await res.json();
|
||||
if (body && typeof body.code === 'string') {
|
||||
return body as BackendError;
|
||||
}
|
||||
} catch {
|
||||
// Body was not JSON
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns a localised message for the given error code via Paraglide. Falls back to INTERNAL_ERROR. */
|
||||
export function getErrorMessage(code: ErrorCode | string | undefined): string {
|
||||
switch (code) {
|
||||
case 'DOCUMENT_NOT_FOUND': return m.error_document_not_found();
|
||||
case 'DOCUMENT_NO_FILE': return m.error_document_no_file();
|
||||
case 'FILE_NOT_FOUND': return m.error_file_not_found();
|
||||
case 'FILE_UPLOAD_FAILED': return m.error_file_upload_failed();
|
||||
case 'USER_NOT_FOUND': return m.error_user_not_found();
|
||||
case 'IMPORT_ALREADY_RUNNING':return m.error_import_already_running();
|
||||
case 'UNAUTHORIZED': return m.error_unauthorized();
|
||||
case 'FORBIDDEN': return m.error_forbidden();
|
||||
case 'VALIDATION_ERROR': return m.error_validation_error();
|
||||
default: return m.error_internal_error();
|
||||
}
|
||||
switch (code) {
|
||||
case 'DOCUMENT_NOT_FOUND':
|
||||
return m.error_document_not_found();
|
||||
case 'DOCUMENT_NO_FILE':
|
||||
return m.error_document_no_file();
|
||||
case 'FILE_NOT_FOUND':
|
||||
return m.error_file_not_found();
|
||||
case 'FILE_UPLOAD_FAILED':
|
||||
return m.error_file_upload_failed();
|
||||
case 'USER_NOT_FOUND':
|
||||
return m.error_user_not_found();
|
||||
case 'IMPORT_ALREADY_RUNNING':
|
||||
return m.error_import_already_running();
|
||||
case 'UNAUTHORIZED':
|
||||
return m.error_unauthorized();
|
||||
case 'FORBIDDEN':
|
||||
return m.error_forbidden();
|
||||
case 'VALIDATION_ERROR':
|
||||
return m.error_validation_error();
|
||||
default:
|
||||
return m.error_internal_error();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user