feat(training): add Paraglide i18n to training UI components and wire SegmentationTrainingCard

- Convert TrainingHistory, OcrTrainingCard, SegmentationTrainingCard, and
  TranscriptionBlock "Nur Segmentierung" badge to use Paraglide message keys
- Add availableSegBlocks to TrainingInfoResponse to expose segmentation
  block count in the training info endpoint
- Wire SegmentationTrainingCard into admin/system page below OCR training card
- Update api.ts with availableSegBlocks field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-13 15:14:27 +02:00
parent 4e08d31e01
commit 86e9c05aaf
9 changed files with 144 additions and 25 deletions

View File

@@ -27,6 +27,7 @@ public class OcrTrainingService {
private final OcrTrainingRunRepository trainingRunRepository;
private final TrainingDataExportService trainingDataExportService;
private final SegmentationTrainingExportService segmentationTrainingExportService;
private final OcrClient ocrClient;
private final OcrHealthClient ocrHealthClient;
private final TranscriptionBlockRepository blockRepository;
@@ -35,6 +36,7 @@ public class OcrTrainingService {
int availableBlocks,
int totalOcrBlocks,
int availableDocuments,
int availableSegBlocks,
boolean ocrServiceAvailable,
OcrTrainingRun lastRun,
List<OcrTrainingRun> runs
@@ -105,6 +107,7 @@ public class OcrTrainingService {
.count();
int totalOcrBlocks = blockRepository.findAll().size();
int availableSegBlocks = segmentationTrainingExportService.querySegmentationBlocks().size();
List<OcrTrainingRun> recentRuns = trainingRunRepository.findTop5ByOrderByCreatedAtDesc();
OcrTrainingRun lastRun = recentRuns.isEmpty() ? null : recentRuns.get(0);
@@ -113,6 +116,7 @@ public class OcrTrainingService {
eligibleBlocks.size(),
totalOcrBlocks,
availableDocuments,
availableSegBlocks,
ocrHealthClient.isHealthy(),
lastRun,
recentRuns
@@ -139,6 +143,7 @@ public class OcrTrainingService {
"availableBlocks", info.availableBlocks(),
"totalOcrBlocks", info.totalOcrBlocks(),
"availableDocuments", info.availableDocuments(),
"availableSegBlocks", info.availableSegBlocks(),
"ocrServiceAvailable", info.ocrServiceAvailable(),
"lastRun", info.lastRun() != null ? info.lastRun() : Map.of(),
"runs", info.runs()

View File

@@ -44,6 +44,7 @@ class OcrControllerTest {
@MockitoBean UserService userService;
@MockitoBean CustomUserDetailsService customUserDetailsService;
@MockitoBean TrainingDataExportService trainingDataExportService;
@MockitoBean SegmentationTrainingExportService segmentationTrainingExportService;
@MockitoBean OcrTrainingService ocrTrainingService;
@Test
@@ -217,7 +218,7 @@ class OcrControllerTest {
@WithMockUser(authorities = "ADMIN")
void getTrainingInfo_returns200_withInfo() throws Exception {
OcrTrainingService.TrainingInfoResponse info =
new OcrTrainingService.TrainingInfoResponse(5, 20, 2, true, null, List.of());
new OcrTrainingService.TrainingInfoResponse(5, 20, 2, 3, true, null, List.of());
when(ocrTrainingService.getTrainingInfo()).thenReturn(info);
mockMvc.perform(get("/api/ocr/training-info"))

View File

@@ -25,6 +25,7 @@ class OcrTrainingServiceTest {
OcrTrainingRunRepository runRepository;
TrainingDataExportService exportService;
SegmentationTrainingExportService segExportService;
OcrClient ocrClient;
OcrHealthClient healthClient;
TranscriptionBlockRepository blockRepository;
@@ -34,14 +35,16 @@ class OcrTrainingServiceTest {
void setUp() {
runRepository = mock(OcrTrainingRunRepository.class);
exportService = mock(TrainingDataExportService.class);
segExportService = mock(SegmentationTrainingExportService.class);
ocrClient = mock(OcrClient.class);
healthClient = mock(OcrHealthClient.class);
blockRepository = mock(TranscriptionBlockRepository.class);
service = new OcrTrainingService(runRepository, exportService, ocrClient, healthClient, blockRepository);
service = new OcrTrainingService(runRepository, exportService, segExportService, ocrClient, healthClient, blockRepository);
when(blockRepository.findAll()).thenReturn(List.of());
when(runRepository.findTop5ByOrderByCreatedAtDesc()).thenReturn(List.of());
when(segExportService.querySegmentationBlocks()).thenReturn(List.of());
}
// ─── Concurrent guard ─────────────────────────────────────────────────────