From 42cf078bb620a5b55f2e3fb16ff91e0a13f79906 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 30 Apr 2026 10:35:04 +0200 Subject: [PATCH 1/3] feat(person-mention): update transcription placeholder with @mention discoverability hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the generic "Type text here..." placeholder in TranscriptionBlock with copy that teaches the @Name trigger inline (Leonie Voss design review, issue #370). No new DOM, no new i18n keys — just the three existing `transcription_block_placeholder` strings. Co-Authored-By: Claude Sonnet 4.6 --- frontend/messages/de.json | 2 +- frontend/messages/en.json | 2 +- frontend/messages/es.json | 2 +- .../src/lib/components/PersonMentionEditor.svelte.spec.ts | 5 +++++ 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/messages/de.json b/frontend/messages/de.json index 28fb6f67..2ab6edc6 100644 --- a/frontend/messages/de.json +++ b/frontend/messages/de.json @@ -503,7 +503,7 @@ "doc_details_more_receivers": "+{count} weitere", "transcription_mode_label": "Transkribieren", "transcription_mode_stop": "Fertig", - "transcription_block_placeholder": "Text hier eingeben...", + "transcription_block_placeholder": "Text eingeben — mit @Name eine Person aus dem Archiv verknüpfen", "transcription_block_save_saving": "Speichere...", "transcription_block_save_saved": "Gespeichert", "transcription_block_save_error": "Nicht gespeichert", diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 1d811734..0a39a394 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -503,7 +503,7 @@ "doc_details_more_receivers": "+{count} more", "transcription_mode_label": "Transcribe", "transcription_mode_stop": "Done", - "transcription_block_placeholder": "Type text here...", + "transcription_block_placeholder": "Type text — use @name to link a person from the archive", "transcription_block_save_saving": "Saving...", "transcription_block_save_saved": "Saved", "transcription_block_save_error": "Not saved", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index 06b805e8..29e50e9f 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -503,7 +503,7 @@ "doc_details_more_receivers": "+{count} más", "transcription_mode_label": "Transcribir", "transcription_mode_stop": "Listo", - "transcription_block_placeholder": "Escriba el texto aquí...", + "transcription_block_placeholder": "Escriba el texto — use @nombre para vincular a una persona del archivo", "transcription_block_save_saving": "Guardando...", "transcription_block_save_saved": "Guardado", "transcription_block_save_error": "No guardado", diff --git a/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts b/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts index 15f04f7d..0a15169c 100644 --- a/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts +++ b/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts @@ -10,6 +10,7 @@ import { cleanup, render } from 'vitest-browser-svelte'; import { page, userEvent } from 'vitest/browser'; import PersonMentionEditorHost from './PersonMentionEditor.test-host.svelte'; import type { components } from '$lib/generated/api'; +import { m } from '$lib/paraglide/messages.js'; type Person = components['schemas']['Person']; type PersonMention = components['schemas']['PersonMention']; @@ -393,6 +394,10 @@ describe('PersonMentionEditor — placeholder behavior', () => { expect(inner!.hasAttribute('data-placeholder')).toBe(false); }); }); + + it('transcription_block_placeholder contains @ mention trigger for discoverability', () => { + expect(m.transcription_block_placeholder()).toContain('@'); + }); }); // ─── Touch target (WCAG 2.2 AA) ────────────────────────────────────────────── -- 2.49.1 From 678d9dab38679185141de43e2ac355ec508b1a4e Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 4 May 2026 15:15:33 +0200 Subject: [PATCH 2/3] refactor(training): extract kurrentLabels helper + clarify query comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract repeated `new java.util.HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION))` into a `kurrentLabels()` helper in TrainingBlockQueryTest and add `import java.util.HashSet`. Add clarifying comments on the two person-scoped queries in TranscriptionBlockRepository explaining that they use `MEMBER OF d.trainingLabels` — aligned with the pre-existing `findEligibleKurrentBlocks()` pattern. Co-Authored-By: Claude Sonnet 4.6 --- .../repository/TranscriptionBlockRepository.java | 4 ++++ .../repository/TrainingBlockQueryTest.java | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/repository/TranscriptionBlockRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/repository/TranscriptionBlockRepository.java index 8e61e09d..5c2d34e2 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/repository/TranscriptionBlockRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/repository/TranscriptionBlockRepository.java @@ -60,6 +60,8 @@ public interface TranscriptionBlockRepository extends JpaRepository findSegmentationBlocks(); + // Uses 'KURRENT_RECOGNITION' MEMBER OF d.trainingLabels — aligned with findEligibleKurrentBlocks() + // which already used this form (changed from d.scriptType = 'KURRENT' in the original queries). @Query(""" SELECT COUNT(b) FROM TranscriptionBlock b JOIN Document d ON d.id = b.documentId @@ -69,6 +71,8 @@ public interface TranscriptionBlockRepository extends JpaRepository(Set.of(TrainingLabel.KURRENT_RECOGNITION))) + .trainingLabels(kurrentLabels()) .build()); kurrentDocId = kurrentDoc.getId(); @@ -123,7 +123,7 @@ class TrainingBlockQueryTest { .originalFilename("karl.pdf") .status(DocumentStatus.UPLOADED) .sender(sender) - .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION))) + .trainingLabels(kurrentLabels()) .build()); UUID annId = annotationRepository.save(annotation(doc.getId())).getId(); blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false)); @@ -158,7 +158,7 @@ class TrainingBlockQueryTest { .originalFilename("karl.pdf") .status(DocumentStatus.UPLOADED) .sender(sender) - .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION))) + .trainingLabels(kurrentLabels()) .build()); UUID annId = annotationRepository.save(annotation(doc.getId())).getId(); blockRepository.save(block(doc.getId(), annId, BlockSource.OCR, false)); @@ -177,7 +177,7 @@ class TrainingBlockQueryTest { .originalFilename("karl.pdf") .status(DocumentStatus.UPLOADED) .sender(karl) - .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION))) + .trainingLabels(kurrentLabels()) .build()); UUID annId = annotationRepository.save(annotation(doc.getId())).getId(); blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false)); @@ -195,7 +195,7 @@ class TrainingBlockQueryTest { .originalFilename("karl.pdf") .status(DocumentStatus.UPLOADED) .sender(sender) - .trainingLabels(new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION))) + .trainingLabels(kurrentLabels()) .build()); UUID annId = annotationRepository.save(annotation(doc.getId())).getId(); blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false)); @@ -218,6 +218,10 @@ class TrainingBlockQueryTest { // ─── helpers ───────────────────────────────────────────────────────────── + private static Set kurrentLabels() { + return new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION)); + } + private DocumentAnnotation annotation(UUID docId) { return DocumentAnnotation.builder() .documentId(docId) -- 2.49.1 From d4f666e98155d3baca34efa6ed6f6d739c92242e Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 4 May 2026 15:16:01 +0200 Subject: [PATCH 3/3] test(person-mention): move i18n test to its own describe block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move `transcription_block_placeholder contains @ mention trigger` out of `describe('PersonMentionEditor — placeholder behavior')` into a new `describe('PersonMentionEditor — i18n message content')` block so each describe group has a single, clear responsibility. Co-Authored-By: Claude Sonnet 4.6 --- .../src/lib/components/PersonMentionEditor.svelte.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts b/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts index 0a15169c..be17e100 100644 --- a/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts +++ b/frontend/src/lib/components/PersonMentionEditor.svelte.spec.ts @@ -394,7 +394,11 @@ describe('PersonMentionEditor — placeholder behavior', () => { expect(inner!.hasAttribute('data-placeholder')).toBe(false); }); }); +}); +// ─── i18n message content ───────────────────────────────────────────────────── + +describe('PersonMentionEditor — i18n message content', () => { it('transcription_block_placeholder contains @ mention trigger for discoverability', () => { expect(m.transcription_block_placeholder()).toContain('@'); }); -- 2.49.1