fix(frontend): show error on training start failure, add aria-live and dismiss to success message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-17 20:46:06 +02:00
parent 0c2175aa07
commit 1e289100a1
4 changed files with 25 additions and 1 deletions

View File

@@ -330,6 +330,7 @@
"comment_time_days": "vor {count} Tag(en)", "comment_time_days": "vor {count} Tag(en)",
"comment_panel_title": "Kommentare", "comment_panel_title": "Kommentare",
"comment_panel_close": "Schließen", "comment_panel_close": "Schließen",
"comp_dismiss": "Schließen",
"doc_panel_tab_metadata": "Metadaten", "doc_panel_tab_metadata": "Metadaten",
"doc_panel_tab_transcription": "Transkription", "doc_panel_tab_transcription": "Transkription",
"doc_panel_tab_discussion": "Diskussion", "doc_panel_tab_discussion": "Diskussion",
@@ -541,6 +542,7 @@
"training_start_btn": "Training starten", "training_start_btn": "Training starten",
"training_in_progress": "…", "training_in_progress": "…",
"training_success": "Training wurde gestartet und abgeschlossen.", "training_success": "Training wurde gestartet und abgeschlossen.",
"training_start_failed": "Training konnte nicht gestartet werden. Bitte versuche es erneut.",
"training_too_few_blocks": "Mindestens 5 geprüfte Blöcke erforderlich (aktuell: {available}).", "training_too_few_blocks": "Mindestens 5 geprüfte Blöcke erforderlich (aktuell: {available}).",
"training_service_down": "OCR-Dienst ist nicht erreichbar.", "training_service_down": "OCR-Dienst ist nicht erreichbar.",
"training_history_heading": "Verlauf", "training_history_heading": "Verlauf",

View File

@@ -330,6 +330,7 @@
"comment_time_days": "{count} day(s) ago", "comment_time_days": "{count} day(s) ago",
"comment_panel_title": "Comments", "comment_panel_title": "Comments",
"comment_panel_close": "Close", "comment_panel_close": "Close",
"comp_dismiss": "Dismiss",
"doc_panel_tab_metadata": "Metadata", "doc_panel_tab_metadata": "Metadata",
"doc_panel_tab_transcription": "Transcription", "doc_panel_tab_transcription": "Transcription",
"doc_panel_tab_discussion": "Discussion", "doc_panel_tab_discussion": "Discussion",
@@ -541,6 +542,7 @@
"training_start_btn": "Start training", "training_start_btn": "Start training",
"training_in_progress": "…", "training_in_progress": "…",
"training_success": "Training started and completed.", "training_success": "Training started and completed.",
"training_start_failed": "Failed to start training. Please try again.",
"training_too_few_blocks": "At least 5 reviewed blocks required (currently: {available}).", "training_too_few_blocks": "At least 5 reviewed blocks required (currently: {available}).",
"training_service_down": "OCR service is unavailable.", "training_service_down": "OCR service is unavailable.",
"training_history_heading": "History", "training_history_heading": "History",

View File

@@ -330,6 +330,7 @@
"comment_time_days": "hace {count} día(s)", "comment_time_days": "hace {count} día(s)",
"comment_panel_title": "Comentarios", "comment_panel_title": "Comentarios",
"comment_panel_close": "Cerrar", "comment_panel_close": "Cerrar",
"comp_dismiss": "Cerrar",
"doc_panel_tab_metadata": "Metadatos", "doc_panel_tab_metadata": "Metadatos",
"doc_panel_tab_transcription": "Transcripción", "doc_panel_tab_transcription": "Transcripción",
"doc_panel_tab_discussion": "Discusión", "doc_panel_tab_discussion": "Discusión",
@@ -541,6 +542,7 @@
"training_start_btn": "Iniciar entrenamiento", "training_start_btn": "Iniciar entrenamiento",
"training_in_progress": "…", "training_in_progress": "…",
"training_success": "Entrenamiento iniciado y completado.", "training_success": "Entrenamiento iniciado y completado.",
"training_start_failed": "No se pudo iniciar el entrenamiento. Por favor, inténtalo de nuevo.",
"training_too_few_blocks": "Se requieren al menos 5 bloques revisados (actualmente: {available}).", "training_too_few_blocks": "Se requieren al menos 5 bloques revisados (actualmente: {available}).",
"training_service_down": "El servicio OCR no está disponible.", "training_service_down": "El servicio OCR no está disponible.",
"training_history_heading": "Historial", "training_history_heading": "Historial",

View File

@@ -21,6 +21,7 @@ let { trainingInfo }: Props = $props();
let training = $state(false); let training = $state(false);
let successMessage = $state<string | null>(null); let successMessage = $state<string | null>(null);
let errorMessage = $state<string | null>(null);
const available = $derived(trainingInfo?.availableBlocks ?? 0); const available = $derived(trainingInfo?.availableBlocks ?? 0);
const tooFewBlocks = $derived(available < 5); const tooFewBlocks = $derived(available < 5);
@@ -30,6 +31,7 @@ const disabled = $derived(training || tooFewBlocks || serviceDown);
async function startTraining() { async function startTraining() {
training = true; training = true;
successMessage = null; successMessage = null;
errorMessage = null;
try { try {
const res = await fetch('/api/ocr/train', { method: 'POST' }); const res = await fetch('/api/ocr/train', { method: 'POST' });
if (res.ok) { if (res.ok) {
@@ -37,7 +39,11 @@ async function startTraining() {
setTimeout(() => { setTimeout(() => {
successMessage = null; successMessage = null;
}, 5000); }, 5000);
} else {
errorMessage = m.training_start_failed();
} }
} catch {
errorMessage = m.training_start_failed();
} finally { } finally {
training = false; training = false;
} }
@@ -72,7 +78,19 @@ async function startTraining() {
{/if} {/if}
{#if successMessage} {#if successMessage}
<p class="mt-2 text-xs text-green-700">{successMessage}</p> <p class="mt-2 flex items-center gap-2 text-xs text-green-700" aria-live="polite">
{successMessage}
<button
type="button"
class="underline hover:no-underline"
onclick={() => (successMessage = null)}
aria-label={m.comp_dismiss()}>×</button
>
</p>
{/if}
{#if errorMessage}
<p class="mt-2 text-xs text-red-600" aria-live="assertive">{errorMessage}</p>
{/if} {/if}
<h3 class="mt-6 mb-3 text-xs font-bold tracking-widest text-ink-3 uppercase"> <h3 class="mt-6 mb-3 text-xs font-bold tracking-widest text-ink-3 uppercase">