Compare commits
4 Commits
feat/issue
...
8c7f3b2e4e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c7f3b2e4e | ||
|
|
52178c2f5b | ||
|
|
54b4b96411 | ||
|
|
c905b81fd3 |
@@ -60,21 +60,25 @@ public interface TranscriptionBlockRepository extends JpaRepository<Transcriptio
|
|||||||
""")
|
""")
|
||||||
List<TranscriptionBlock> findSegmentationBlocks();
|
List<TranscriptionBlock> 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("""
|
@Query("""
|
||||||
SELECT COUNT(b) FROM TranscriptionBlock b
|
SELECT COUNT(b) FROM TranscriptionBlock b
|
||||||
JOIN Document d ON d.id = b.documentId
|
JOIN Document d ON d.id = b.documentId
|
||||||
WHERE b.source = 'MANUAL'
|
WHERE b.source = 'MANUAL'
|
||||||
AND d.sender.id = :personId
|
AND d.sender.id = :personId
|
||||||
AND d.scriptType = 'HANDWRITING_KURRENT'
|
AND 'KURRENT_RECOGNITION' MEMBER OF d.trainingLabels
|
||||||
""")
|
""")
|
||||||
long countManualKurrentBlocksByPerson(@Param("personId") UUID personId);
|
long countManualKurrentBlocksByPerson(@Param("personId") UUID personId);
|
||||||
|
|
||||||
|
// 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("""
|
@Query("""
|
||||||
SELECT b FROM TranscriptionBlock b
|
SELECT b FROM TranscriptionBlock b
|
||||||
JOIN Document d ON d.id = b.documentId
|
JOIN Document d ON d.id = b.documentId
|
||||||
WHERE b.source = 'MANUAL'
|
WHERE b.source = 'MANUAL'
|
||||||
AND d.sender.id = :personId
|
AND d.sender.id = :personId
|
||||||
AND d.scriptType = 'HANDWRITING_KURRENT'
|
AND 'KURRENT_RECOGNITION' MEMBER OF d.trainingLabels
|
||||||
""")
|
""")
|
||||||
List<TranscriptionBlock> findManualKurrentBlocksByPerson(@Param("personId") UUID personId);
|
List<TranscriptionBlock> findManualKurrentBlocksByPerson(@Param("personId") UUID personId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
import org.raddatz.familienarchiv.PostgresContainerConfig;
|
import org.raddatz.familienarchiv.PostgresContainerConfig;
|
||||||
import org.raddatz.familienarchiv.config.FlywayConfig;
|
import org.raddatz.familienarchiv.config.FlywayConfig;
|
||||||
import org.raddatz.familienarchiv.model.*;
|
import org.raddatz.familienarchiv.model.*;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||||
@@ -24,6 +25,7 @@ class TrainingBlockQueryTest {
|
|||||||
@Autowired TranscriptionBlockRepository blockRepository;
|
@Autowired TranscriptionBlockRepository blockRepository;
|
||||||
@Autowired DocumentRepository documentRepository;
|
@Autowired DocumentRepository documentRepository;
|
||||||
@Autowired AnnotationRepository annotationRepository;
|
@Autowired AnnotationRepository annotationRepository;
|
||||||
|
@Autowired PersonRepository personRepository;
|
||||||
|
|
||||||
private UUID kurrentDocId;
|
private UUID kurrentDocId;
|
||||||
private UUID typewriterDocId;
|
private UUID typewriterDocId;
|
||||||
@@ -36,7 +38,7 @@ class TrainingBlockQueryTest {
|
|||||||
.title("Kurrent Brief")
|
.title("Kurrent Brief")
|
||||||
.originalFilename("kurrent.pdf")
|
.originalFilename("kurrent.pdf")
|
||||||
.status(DocumentStatus.UPLOADED)
|
.status(DocumentStatus.UPLOADED)
|
||||||
.trainingLabels(new java.util.HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION)))
|
.trainingLabels(kurrentLabels())
|
||||||
.build());
|
.build());
|
||||||
kurrentDocId = kurrentDoc.getId();
|
kurrentDocId = kurrentDoc.getId();
|
||||||
|
|
||||||
@@ -111,8 +113,105 @@ class TrainingBlockQueryTest {
|
|||||||
assertThat(result).hasSize(2);
|
assertThat(result).hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── sender-based queries ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findManualKurrentBlocksByPerson_includesBlockFromKurrentLabelledDocument() {
|
||||||
|
Person sender = personRepository.save(Person.builder().firstName("Karl").lastName("Test").build());
|
||||||
|
Document doc = documentRepository.save(Document.builder()
|
||||||
|
.title("Brief von Karl")
|
||||||
|
.originalFilename("karl.pdf")
|
||||||
|
.status(DocumentStatus.UPLOADED)
|
||||||
|
.sender(sender)
|
||||||
|
.trainingLabels(kurrentLabels())
|
||||||
|
.build());
|
||||||
|
UUID annId = annotationRepository.save(annotation(doc.getId())).getId();
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false));
|
||||||
|
|
||||||
|
List<TranscriptionBlock> result = blockRepository.findManualKurrentBlocksByPerson(sender.getId());
|
||||||
|
|
||||||
|
assertThat(result).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findManualKurrentBlocksByPerson_excludesDocumentWithoutKurrentLabel() {
|
||||||
|
Person sender = personRepository.save(Person.builder().firstName("Karl").lastName("Test").build());
|
||||||
|
Document doc = documentRepository.save(Document.builder()
|
||||||
|
.title("Brief von Karl")
|
||||||
|
.originalFilename("karl.pdf")
|
||||||
|
.status(DocumentStatus.UPLOADED)
|
||||||
|
.sender(sender)
|
||||||
|
.build());
|
||||||
|
UUID annId = annotationRepository.save(annotation(doc.getId())).getId();
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false));
|
||||||
|
|
||||||
|
List<TranscriptionBlock> result = blockRepository.findManualKurrentBlocksByPerson(sender.getId());
|
||||||
|
|
||||||
|
assertThat(result).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findManualKurrentBlocksByPerson_excludesOcrBlocks() {
|
||||||
|
Person sender = personRepository.save(Person.builder().firstName("Karl").lastName("Test").build());
|
||||||
|
Document doc = documentRepository.save(Document.builder()
|
||||||
|
.title("Brief von Karl")
|
||||||
|
.originalFilename("karl.pdf")
|
||||||
|
.status(DocumentStatus.UPLOADED)
|
||||||
|
.sender(sender)
|
||||||
|
.trainingLabels(kurrentLabels())
|
||||||
|
.build());
|
||||||
|
UUID annId = annotationRepository.save(annotation(doc.getId())).getId();
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.OCR, false));
|
||||||
|
|
||||||
|
List<TranscriptionBlock> result = blockRepository.findManualKurrentBlocksByPerson(sender.getId());
|
||||||
|
|
||||||
|
assertThat(result).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findManualKurrentBlocksByPerson_excludesOtherSender() {
|
||||||
|
Person karl = personRepository.save(Person.builder().firstName("Karl").lastName("Test").build());
|
||||||
|
Person anna = personRepository.save(Person.builder().firstName("Anna").lastName("Test").build());
|
||||||
|
Document doc = documentRepository.save(Document.builder()
|
||||||
|
.title("Brief von Karl")
|
||||||
|
.originalFilename("karl.pdf")
|
||||||
|
.status(DocumentStatus.UPLOADED)
|
||||||
|
.sender(karl)
|
||||||
|
.trainingLabels(kurrentLabels())
|
||||||
|
.build());
|
||||||
|
UUID annId = annotationRepository.save(annotation(doc.getId())).getId();
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false));
|
||||||
|
|
||||||
|
List<TranscriptionBlock> result = blockRepository.findManualKurrentBlocksByPerson(anna.getId());
|
||||||
|
|
||||||
|
assertThat(result).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void countManualKurrentBlocksByPerson_matchesFindResult() {
|
||||||
|
Person sender = personRepository.save(Person.builder().firstName("Karl").lastName("Test").build());
|
||||||
|
Document doc = documentRepository.save(Document.builder()
|
||||||
|
.title("Brief von Karl")
|
||||||
|
.originalFilename("karl.pdf")
|
||||||
|
.status(DocumentStatus.UPLOADED)
|
||||||
|
.sender(sender)
|
||||||
|
.trainingLabels(kurrentLabels())
|
||||||
|
.build());
|
||||||
|
UUID annId = annotationRepository.save(annotation(doc.getId())).getId();
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, false));
|
||||||
|
blockRepository.save(block(doc.getId(), annId, BlockSource.MANUAL, true));
|
||||||
|
|
||||||
|
long count = blockRepository.countManualKurrentBlocksByPerson(sender.getId());
|
||||||
|
|
||||||
|
assertThat(count).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
// ─── helpers ─────────────────────────────────────────────────────────────
|
// ─── helpers ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
private static Set<TrainingLabel> kurrentLabels() {
|
||||||
|
return new HashSet<>(Set.of(TrainingLabel.KURRENT_RECOGNITION));
|
||||||
|
}
|
||||||
|
|
||||||
private DocumentAnnotation annotation(UUID docId) {
|
private DocumentAnnotation annotation(UUID docId) {
|
||||||
return DocumentAnnotation.builder()
|
return DocumentAnnotation.builder()
|
||||||
.documentId(docId)
|
.documentId(docId)
|
||||||
|
|||||||
@@ -502,7 +502,7 @@
|
|||||||
"doc_details_more_receivers": "+{count} weitere",
|
"doc_details_more_receivers": "+{count} weitere",
|
||||||
"transcription_mode_label": "Transkribieren",
|
"transcription_mode_label": "Transkribieren",
|
||||||
"transcription_mode_stop": "Fertig",
|
"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_saving": "Speichere...",
|
||||||
"transcription_block_save_saved": "Gespeichert",
|
"transcription_block_save_saved": "Gespeichert",
|
||||||
"transcription_block_save_error": "Nicht gespeichert",
|
"transcription_block_save_error": "Nicht gespeichert",
|
||||||
|
|||||||
@@ -502,7 +502,7 @@
|
|||||||
"doc_details_more_receivers": "+{count} more",
|
"doc_details_more_receivers": "+{count} more",
|
||||||
"transcription_mode_label": "Transcribe",
|
"transcription_mode_label": "Transcribe",
|
||||||
"transcription_mode_stop": "Done",
|
"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_saving": "Saving...",
|
||||||
"transcription_block_save_saved": "Saved",
|
"transcription_block_save_saved": "Saved",
|
||||||
"transcription_block_save_error": "Not saved",
|
"transcription_block_save_error": "Not saved",
|
||||||
|
|||||||
@@ -502,7 +502,7 @@
|
|||||||
"doc_details_more_receivers": "+{count} más",
|
"doc_details_more_receivers": "+{count} más",
|
||||||
"transcription_mode_label": "Transcribir",
|
"transcription_mode_label": "Transcribir",
|
||||||
"transcription_mode_stop": "Listo",
|
"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_saving": "Guardando...",
|
||||||
"transcription_block_save_saved": "Guardado",
|
"transcription_block_save_saved": "Guardado",
|
||||||
"transcription_block_save_error": "No guardado",
|
"transcription_block_save_error": "No guardado",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { cleanup, render } from 'vitest-browser-svelte';
|
|||||||
import { page, userEvent } from 'vitest/browser';
|
import { page, userEvent } from 'vitest/browser';
|
||||||
import PersonMentionEditorHost from './PersonMentionEditor.test-host.svelte';
|
import PersonMentionEditorHost from './PersonMentionEditor.test-host.svelte';
|
||||||
import type { components } from '$lib/generated/api';
|
import type { components } from '$lib/generated/api';
|
||||||
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
|
|
||||||
type Person = components['schemas']['Person'];
|
type Person = components['schemas']['Person'];
|
||||||
type PersonMention = components['schemas']['PersonMention'];
|
type PersonMention = components['schemas']['PersonMention'];
|
||||||
@@ -395,6 +396,14 @@ describe('PersonMentionEditor — placeholder behavior', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── i18n message content ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
describe('PersonMentionEditor — i18n message content', () => {
|
||||||
|
it('transcription_block_placeholder contains @ mention trigger for discoverability', () => {
|
||||||
|
expect(m.transcription_block_placeholder()).toContain('@');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ─── Touch target (WCAG 2.2 AA) ──────────────────────────────────────────────
|
// ─── Touch target (WCAG 2.2 AA) ──────────────────────────────────────────────
|
||||||
|
|
||||||
describe('PersonMentionEditor — touch target', () => {
|
describe('PersonMentionEditor — touch target', () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user